2010-11-30

mediaplayerを作ってみる(8)-2

続き。string.xmlから。

    <string name="no_title">no title</string>

追加。次、main.xml。レイアウトの一番上に

    <Spinner
        android:id="@+id/spinner"
        android:layout_width="fill_parent"
        android:layout_height="30dp"
        android:background="@color/red">
    </Spinner>

後、TextViewに

android:text="@string/no_title"

追加。なんとなく。次、Activity。

フィールド

private static final String FILE_SEP = File.separator; 削除。

musicListをmusicFileListに変更。名前だけ。
編集→検索/置換で。ただし、すべて置換はやめたほうがいい。

private ArrayList<String> musicDirList;
private MusicListAdapter listAdapter;
private String musicDirName;
private Spinner spinner;

↑4つ追加。そんで、onCreateを

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.main);
       
        //DirListMakerの生成
        DirListMaker dlm = new DirListMaker();
       
        //spinnerに渡すリストの作成
        ArrayList<String> dirList = new ArrayList<String>();
        dirList.add(SD_PATH);
        musicDirList = dlm.dirListMaker(dirList, "mp3");
       
        //spinnerの取得とArrayAdapterの生成及びセット
        spinner = (Spinner)findViewById(R.id.spinner);
        ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_spinner_item, musicDirList);
       
        spinnerAdapter.setDropDownViewResource(
                android.R.layout.simple_spinner_dropdown_item);

        spinner.setAdapter(spinnerAdapter);
        spinner.setOnItemSelectedListener(this);
       
        //musicFileListの生成
        musicFileList = new ArrayList<String>();
       
        //リストビューの取得と諸々のこと
        listView = (ListView)findViewById(R.id.listView);
        listView.setItemsCanFocus(false);
        listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
       
        //クリックされた事を検知。selectedとの違いは分かってません。
        listView.setOnItemClickListener(this);
       
        //musicPlayerの引数に渡すので先に取得
        titleView = (TextView)findViewById(R.id.titleView);

        //musicPlayerの生成とmusicNumの取得
        musicPlayer = new MusicPlayer(titleView);
       
        pauseFlag = false;        //一時停止解除
        changeMusicFlag = false;//曲変更のお知らせ。
       
        //listAdapterの生成
        listAdapter = new MusicListAdapter(this,
                R.layout.rowdata, musicFileList, listView);
       
        //musicList変更用
        flm = new FileListMaker();
    }

こんな↑感じ。それから、

    //これも@Override出来ない。なんか残念。spinnerのイベント処理
    public void onItemSelected(AdapterView<?> parent,
            View view, int position, long id) {

        //選択されたアイテムの取得。
        musicDirName = musicDirList.get(position);
       
        //リストの詰め替え準備
        musicFileList.clear();
        //リストの詰め替え
        flm.fileListMaker(musicDirName, "mp3", musicFileList);
        //listViewの変更
        listView.setAdapter(listAdapter);

        //色々通知。
        musicPlayer.setMusicDir(musicDirName);
        musicPlayer.setMusicList(musicFileList);
        musicPlayer.setListView(listView);
    }

確かこれだけ。後は、MusicPlayer。

フィールドの

    private static final String SD_PATH = //SDのパス
        Environment.getExternalStorageDirectory().getPath();

削除。そんで、コンストラクタを変更してセッター追加。


    public MusicPlayer(TextView tv) {
      
        super();
        titleView = tv;
        musicNum = 0;
      
        super.setOnCompletionListener(this);
    }
  
    public void setMusicList(ArrayList<String> array) {
        musicList = array;
    }
  
    public void setListView(ListView lv) {
        listView = lv;
    }
  
    public void setMusicDir(String name) {
        musicDirName = name;
    }

それから、

listView.setSelection(musicNum - 1);

に変更。これは、なんとなく。見た目の問題。で、最後が

            super.setDataSource(musicDirName
                    + FILE_SEP + musicList.get(musicNum));

に変更。これは、結構重要。やらないと音楽が聴けません。
以上。だと思います。

なんか、段々それなりになってきた様な気がしないでもない。
でもねー。やっぱりねー。前に作ったのと同じ問題発生中。
強制終了になることはない。と思いたい。

ディレクトリAの5曲目を再生中に、ディレクトリBに変えると
Aの6曲目ではなく、Bの6曲目がかかります。
ちなみにBに6曲目がないと・・・。

1曲目に戻ります。そんだけ。
まあ、ぼちぼち修正します。

次は、ディレクトリをまたいでの連続再生。
問題を解消しないままに。たぶん。

追記

    public void onNothingSelected(AdapterView<?> arg0) {
        // TODO 自動生成されたメソッド・スタブ
       
    }

これ、忘れてました。追加しろと言われたので、言われるままに。

mediaplayerを作ってみる(8)-1

今回はspinner。予定どおり。
参考はここここ、そしてここ
何か、嫌がらせの様だ。別にそんな気はないですが。

(8)-1では、3つ目のここを参考にして作ったclass + αを。
まあ、参考というかちょっと変えただけですが。そんなんばっか。
まあ、とりあえず。

SD内の音楽ファイルの入ったディレクトリを、
ArrayListに詰め込みます。音楽ファイル以外にも使えます。たぶん。
いやきっと。参考にしたとこを考えると。載せときます。

 package net.asasvata.listmaker;

import java.io.File;
import java.util.ArrayList;

public class DirListMaker {
    private final String FILE_SEP = File.separator;
  
    //ファイル1種類用
    public ArrayList<String> dirListMaker(ArrayList<String> list, String ext) {
        //ArrayListの生成
        ArrayList<String> array = new ArrayList<String>();
      
        int m = 0; int n = 0;
        while (list.size() > m) {
          
            File subDir = new File(list.get(m));
            String[] subFileName = subDir.list();
          
            n = 0;
            while (subFileName.length > n) {
                File subFile = new File(subDir.getPath() + FILE_SEP + subFileName[n]);
              
                if (subFile.isDirectory()) {
                    list.add(subDir.getPath() + FILE_SEP + subFileName[n]);
                  
                } else if (subFile.isFile() && subFile.getName().endsWith(ext)) {
                  
                    if (!array.contains(list.get(m))) {
                        array.add(list.get(m));
                    }
                }
                n++;
            }
            m++;
        }
        return array;      
    }
  
    //ファイル2種類用
    public ArrayList<String> dirListMaker(ArrayList<String> list, String ext1, String ext2) {
        ArrayList<String> array = new ArrayList<String>();
        int m = 0; int n = 0;
        while (list.size() > m) {
            File subDir = new File(list.get(m));
            String[] subFileName = subDir.list();
            n = 0;
            while (subFileName.length > n) {
                File subFile = new File(subDir.getPath() + FILE_SEP + subFileName[n]);
                if (subFile.isDirectory()) {
                    list.add(subDir.getPath() + FILE_SEP + subFileName[n]);
                } else if (subFile.isFile() &&
                        (subFile.getName().endsWith(ext1) || subFile.getName().endsWith(ext2))) {
                  
                    if (!array.contains(list.get(m))) {
                        array.add(list.get(m));
                    }
                }
                n++;
            }
            m++;
        }
        return array;      
    }
}

パッケージも分けました。なんとなく。javaっぽいかと。
ファイル2種類用も作りました。元ネタと同じ書き方なので。
動くと思います。確認してませんが。

違うのはファイルをリストに詰めるのではなく、ディレクトリを詰めること。
まあ、そんだけしか変えてません。

後、もう一個。ついでに作りました。

package net.asasvata.listmaker;

import java.io.File;
import java.util.ArrayList;

public class FileListMaker {
    private final String FILE_SEP = File.separator;
   
    //ファイル1種類用
    public void fileListMaker(String name, String ext, ArrayList<String> list) {
       
        File musicFile = new File(name);
        String[] musicFileList = musicFile.list();
       
        for (String fileName : musicFileList) {
            File file = new File(name + FILE_SEP + fileName);
           
            if (file.isFile() && fileName.endsWith(ext)) {
                list.add(fileName);
            }
        }
    }
   
    //ファイル2種類用
    public void fileListMaker(String name, String ext1, String ext2, ArrayList<String> list) {
        File musicFile = new File(name);
        String[] musicFileList = musicFile.list();
        for (String fileName : musicFileList) {
            File file = new File(name + FILE_SEP + fileName);
            if (file.isFile() && (fileName.endsWith(ext1) || fileName.endsWith(ext2))) {
                list.add(fileName);
            }
        }
    }
}

まあ、なんですなdirListMakerで作ったディレクトリリストに入ってる
ファイルを別のリストに詰め込む。そんな感じ。spinnerを介して。

で、こいつらを使ったコードを(8)-2に載せときます。

mediaplayerを作ってみる(7)

(5)のしたの方に書いたのをもう一度載せときます。

参考と言うかまんまなのはここ

Android Manifestのactivityのとこを、

        <activity android:name=".SDMediaPlayerActivity"
                  android:label="@string/app_name"
                  android:screenOrientation="portrait"
                  android:configChanges="orientation|keyboardHidden">

こんな感じに、下2行追加しておくと、縦画面固定で
横にしても音楽が、かかりっぱなしの暴走をしなくなります。
横画面を切り替えたい方は、頑張ってください。僕は縦固定で。

後、MediaPlayerでサポートされてるファイル形式はここ

今回の変更は前回の修正と、まあ、色々と。

とりあえず、参考にしたのはここここ。この書き方良くないですかね。
まあ、変える気はありませんが。今のとこ。

rowdata.xml

<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/checkedTextView"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:minHeight="?android:attr/listPreferredItemHeight"
    android:paddingLeft="10dip"
    android:gravity="center"
    android:textColor="@color/green">
</CheckedTextView>

CheckedTextView。まんまです。
で、 MusicListAdapter classを作成

package net.asasvata.sdmediaplayer;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckedTextView;
import android.widget.ListView;
//import android.widget.TextView;

public class MusicListAdapter extends ArrayAdapter<String> {
    private LayoutInflater inflater;
    private int layoutId;
    private ListView listView;

    public MusicListAdapter(Context context, int layoutId, ArrayList<String> objects, ListView listView) {
        super(context, 0, objects);
        this.inflater =
            (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        this.layoutId = layoutId;
       
        this.listView = listView;

    }
   
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = inflater.inflate(layoutId, parent, false);
        }
        //String data = getItem(position);
        ((CheckedTextView)convertView).setText((position + 1) + ": " +
                listView.getItemAtPosition(position).toString());
        if(position == listView.getCheckedItemPosition())
            ((CheckedTextView)convertView).setBackgroundColor(Color.DKGRAY);
        else
            ((CheckedTextView)convertView).setBackgroundColor(Color.TRANSPARENT);
         return convertView;
    }
}

表示内容以外はそのままです。有難い。中身は、よく分かりませんが。
次は、MusicPlayer。フィールドに

private ListView listView;

を追加。それから、コンストラクタの引数に

ListView lv

を追加。コンストラクタの中に

listView = lv;

を追加。で、playMusicの中、setTitleの下あたりに

        listView.clearChoices();
        listView.setItemChecked(musicNum, true);
        listView.setSelection(musicNum); 

を追加。なんかこれがいいみたい。色々試した結果。
僕のイメージには、あってる。今のところ。
そいから、Activity。フィールドに

private int musicNum_listClicked;

なんか変な名前。まあ、ね。
で、onCreateの中を、


listView = (ListView)findViewById(R.id.listView);//ここは、前と同じ。上書き。
        listView.setItemsCanFocus(false);
        listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
       
        //MusicListAdapterの生成
        MusicListAdapter listAdapter =
                new MusicListAdapter(this, R.layout.rowdata, musicList, listView);


んな感じ。それから、onItemClickの中を

        listPosition = position;//ここは、前と同じ。上書き。
        musicNum_listClicked = musicPlayer.getMusicNum();
        changeMusicFlag = true;

に変更。setTitleは削除。
 で、onClickStartを

    public void onClickStart(View view) {
        if (!musicPlayer.isPlaying()){
          
            //停止中にlistViewで曲変更した場合
            if (changeMusicFlag) {
              
                musicPlayer.setMusicNum(listPosition);
                musicPlayer.playMusic();
                changeMusicFlag = false;
            }
          
            if (pauseFlag) {    //一時停止中なら
              
                musicPlayer.start();
                pauseFlag = false;
              
            } else {
              
                musicPlayer.playMusic();
                changeMusicFlag = false;
            }
        }
        //再生中で曲選択が変わってたら。つまり、listViewで選択した場合です。
        if (changeMusicFlag && musicNum_listClicked 
== musicPlayer.getMusicNum()) {  

            musicPlayer.setMusicNum(listPosition);
            musicPlayer.playMusic();
            changeMusicFlag = false;          
        } else {
            changeMusicFlag = false;
        }
    }

どこを変えたか分かりにくいので。

musicNum_listClicked == musicPlayer.getMusicNum()
これ↑は、 連続再生で次に進んでなかったらと言うことです。
後、setTitle()の中の、
changeMusicFlag = ture;を
changeMusicFlag = false;に。
間違ってました。

動きとしては、

停止中
・listViewをクリックするとグレーになる。
・listViewをクリックしただけではタイトルは変わらない。
・再生するとタイトルも変わる。
・進む、戻るはタイトルが変わる。listViewの色は変わらない。
・listViewクリックと進む、戻るは最後の選択が有効。

再生中
・listViewの動きは停止中と同じ。連続再生で次の曲にいくまで有効。
・進む、戻るは曲・タイトル・listViewすべて変わる。

多分。そんな感じ。要確認。
次は、spinner。名前が好きなので。使います。予定ですが。

2010-11-28

mediaplayerを作ってみる(6)-2

続き。(6)-1からの。Activityを。

package net.asasvata.sdmediaplayer;

import java.io.File;
import java.util.ArrayList;

import android.app.Activity;
import android.graphics.Typeface;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.Window;
import android.widget.ArrayAdapter;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;

public class SDMediaPlayerActivity extends Activity
        implements AdapterView.OnItemClickListener {
   
    //フィールド
    private static final String SD_PATH = //SDのパス
        Environment.getExternalStorageDirectory().getPath();
    private static final String FILE_SEP = File.separator;//pathの区切り文字
   
   
    private ArrayList<String> musicList;
    private MusicPlayer musicPlayer;   

    private boolean pauseFlag;//一時停止の判定用
    private boolean changeMusicFlag;//musicNumの変更判定用
    private int listPosition;//listViewが、クリックされた時の位置を保持
   
    private ListView listView;//ディレクトリ内の曲のリスト表示
    private TextView titleView;//現在選択されている曲の表示

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.main);
               
        //musicListの生成と曲の追加
        musicList = new ArrayList<String>();
       
        File musicFile = new File(SD_PATH + FILE_SEP + "deepfm");
        String[] musicFileList = musicFile.list();
       
        for(String fileName : musicFileList) {
            File f = new File(SD_PATH + FILE_SEP + "deepfm"
                    + FILE_SEP + fileName);
            if(f.isFile() && fileName.endsWith("mp3"))
                musicList.add(fileName);
        }
       
        listView = (ListView)findViewById(R.id.listView);
       
        //ArrayAdapterの生成
        ArrayAdapter<String> listAdapter =
                new ArrayAdapter<String>(this, R.layout.rowdata, musicList);
       
        //listViewにlistAdapterをセット。
        listView.setAdapter(listAdapter);
        //クリックされた事を検知。selectedとの違いは分かってません。
        listView.setOnItemClickListener(this);
       
        //musicPlayerの引数に渡すので先に取得
        titleView = (TextView)findViewById(R.id.titleView);

        //musicPlayerの生成とmusicNumの取得
        musicPlayer = new MusicPlayer(musicList, titleView);

        //タイトルのセット。flagの初期化も。
        setTitle();
    }
   
    //とりあえず。
    @Override
    public void onStop() {
        super.onStop();
        musicPlayer.stop();
    }
   
    //なぜかOverride出来ない。listViewがクリックされた時の処理。
    //@Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        //曲の選択をするだけ。再生はしない。とりあえず。
        listPosition = position;
        setTitle(position);
    }

    //ボタンが押されたときの処理。レイアウトの右から順に。
    //戻る
    public void onClickBack(View view) {
        int n = musicPlayer.getMusicNum() - 1;//とりあえず減らす
       
        if (n < 0) {
            n = musicList.size() - 1;//最後の曲を指定
            musicPlayer.setMusicNum(n);
           
            if (musicPlayer.isPlaying()) musicPlayer.playMusic();
            else setTitle();
           
        } else {
            musicPlayer.setMusicNum(n);
           
            if (musicPlayer.isPlaying()) musicPlayer.playMusic();
            else setTitle();
        }
    }
    //進む
    public void onClickNext(View view) {
        int n = musicPlayer.getMusicNum() + 1;//とりあえず増やす。
       
        if (n < musicList.size()) {
            musicPlayer.setMusicNum(n);
           
            if (musicPlayer.isPlaying()) musicPlayer.playMusic();
            else setTitle();
           
        } else {
            n = 0;//1曲目を指定
            musicPlayer.setMusicNum(n);
           
            if (musicPlayer.isPlaying()) musicPlayer.playMusic();
            else setTitle();
        }
    }
    //再生   
    public void onClickStart(View view) {
        if (!musicPlayer.isPlaying()){
           
            //停止中にlistViewで曲変更した場合
            if (musicPlayer.getMusicNum() != listPosition) {
               
                musicPlayer.setMusicNum(listPosition);
                musicPlayer.playMusic();
                changeMusicFlag = false;
            }
           
            if (pauseFlag) {    //一時停止中なら
               
                musicPlayer.start();
                pauseFlag = false;
               
            } else {
               
                musicPlayer.playMusic();
                changeMusicFlag = false;
            }
        }
        if (changeMusicFlag) {    //再生中で曲選択が変わってたら。
                                //つまり、listViewで選択した場合です。
            musicPlayer.setMusicNum(listPosition);
            musicPlayer.playMusic();
            changeMusicFlag = false;
        }
    }
    //一時停止
    public void onClickPause(View view) {
        if (musicPlayer.isPlaying()) {
            musicPlayer.pause();
            pauseFlag = true;    //ここのみtrueに。
        }
    }
    //停止
    public void onClickStop(View view) {
        if(musicPlayer.isPlaying()) musicPlayer.stop();
        else pauseFlag = false;    //一時停止解除
    }
    //skip。これは、そのまま。
    public void onClickSkip(View view) {
        if(musicPlayer.isPlaying()) musicPlayer.skipMusic();
    }
   
    //タイトルをセット。
    public void setTitle() {
        pauseFlag = false;        //一時停止解除
        changeMusicFlag = true;//曲変更のお知らせ。
        int n = musicPlayer.getMusicNum();
        titleView.setText((n + 1) + ": " + musicList.get(n));
    }
    //タイトルをセット。listViewがクリックされた時用
    public void setTitle(int num) {
        pauseFlag = false;       
        changeMusicFlag = true;
        titleView.setText((num + 1) + ": " + musicList.get(num));
    }
}

こんな感じ↓。

















まあ、アレのイメージです。
前のよりボタンを増やしすぎて、だんだんワケが分からなくなってきた。

進むとか戻るはいるのか。listViewをタッチして再生した方がいいか。
動きが変なとこもあるかも。まあ、だいたいで。

次は、また大きく変わるかも。変わらないかも。

mediaplayerを作ってみる(6)-1

今更ですが、target は Android1.6です。
かなり変更してしまいました。2回に分けて載せときます。
とりあえず、string.xmlから。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">SDMP</string>
    <string name="back_button">戻る</string>
    <string name="next_button">進む</string>
    <string name="start_button">再生</string>
    <string name="pause_button">一時停止</string>
    <string name="stop_button">停止</string>
    <string name="skip_button">skip</string>
    <color name="violet">#400a40</color>
    <color name="black">#010101</color>
    <color name="green">#40e91f</color>
    <color name="red">#b00a0a</color>
</resources>

ボタンが増えて、色も変えてます。
 次は、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"
    android:background="@color/violet">
    <TextView
        android:id="@+id/titleView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textSize="16sp"
        android:background="@color/black"
        android:textColor="@color/red">
    </TextView>
    <ListView
        android:id="@+id/listView"
        android:layout_width="fill_parent"
        android:layout_height="240dp">
    </ListView>
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="30dp"
        android:background="@color/red">
           <Button
            android:id="@+id/backButton"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:layout_weight="1"
            android:gravity="center"
            android:background="@color/black"
            android:textColor="@color/red"
            android:text="@string/back_button"
            android:onClick="onClickBack">
        </Button>
           <Button
            android:id="@+id/nextButton"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:layout_weight="1"
            android:gravity="center"
            android:background="@color/black"
            android:textColor="@color/red"
            android:text="@string/next_button"
            android:onClick="onClickNext">
        </Button>
           <Button
            android:id="@+id/startButton"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:layout_weight="2"
            android:background="@color/black"
            android:textColor="@color/red"
            android:text="@string/start_button"
            android:onClick="onClickStart">
        </Button>
           <Button
            android:id="@+id/pauseButton"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:layout_weight="1"
            android:background="@color/black"
            android:textColor="@color/red"
            android:text="@string/pause_button"
            android:onClick="onClickPause">
        </Button>
        <Button
            android:id="@+id/stopButton"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:layout_weight="1"
            android:gravity="center"
            android:background="@color/black"
            android:textColor="@color/red"
            android:text="@string/stop_button"
            android:onClick="onClickStop">
        </Button>
    </LinearLayout>
    <Button
        android:id="@+id/skipButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/skip_button"
        android:onClick="onClickSkip">
    </Button>
</LinearLayout>

色と文字の配置が増えてます。前作ってたのより増えてる。色々。
次は、ListViewのレイアウト rowdata.xml。 res/layoutの下に配置。

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textView"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textColor="@color/green">
</TextView>

ほぼ、javadrive
 次は、MusicPlayer classを載せときます。

package net.asasvata.sdmediaplayer;

import java.io.File;
import java.util.ArrayList;

import android.media.MediaPlayer;
import android.os.Environment;
import android.util.Log;
import android.widget.TextView;

public class MusicPlayer extends MediaPlayer
                implements MediaPlayer.OnCompletionListener {
   
    private static final String SD_PATH = //SDのパス
        Environment.getExternalStorageDirectory().getPath();
    private static final String FILE_SEP = File.separator;//pathの区切り文字
   
    private ArrayList<String> musicList;
    private int musicNum;
   
    private TextView titleView;//タイトル表示用
   
    //引数にTextView追加。
    public MusicPlayer(ArrayList<String> list, TextView tv) {
       
        super();
        this.musicList = list;
        titleView = tv;
        musicNum = 0;
       
        super.setOnCompletionListener(this);
    }
   
    public int getMusicNum() {
        return musicNum;
    }
   
    public void setMusicNum(int num) {
        musicNum = num;
    }
   
    //音楽ファイルのパスを取得してスタート。
    public void playMusic() {
       
        super.stop();
        super.reset();//これが要る様だ。
        setTitle();
       
        try{
            super.setDataSource(SD_PATH + FILE_SEP + "deepfm"
                    + FILE_SEP + musicList.get(musicNum));
           
            super.prepare();
            super.seekTo(0);
            super.start();
           
        } catch (Exception e) {
            Log.v("playMusic", "" + e);//なんとなく変更。
        }
    }
   
    //残り3秒まで飛びます。
    public void skipMusic() {
       
        int duration = super.getDuration();
        super.seekTo(duration - 3000);
    }
       
    //曲が終わったときの処理
    public void onCompletion(MediaPlayer mp) {
        if (++musicNum < musicList.size()) {
           
            playMusic();
           
        } else {
           
            musicNum = 0;
            playMusic();
        }
       
    }
   
    //タイトルをセット。
    public void setTitle() {
        titleView.setText((musicNum + 1) + ": " + musicList.get(musicNum));
    }
}

次の回へ。

2010-11-27

mediaplayerを作ってみる(5)

ちょっとおかしな事に気づきました。
MusicPlayer class。  MediaPlayerを継承してる意味がない。
外してもいいですが、本来意図していた方向に。

フィールドのmediaPlayerを削除

コンストラクタの  mediaPlayer = new MediaPlayer(); 削除

 後は、mediaPlayer をひたすら super に変更。
 isPlayMusic() 削除。
stopMusic()  も削除。

SDMediaPlayerの方は、ついでに地味に変更しときます。
(2)でこれの方がいいかもと書いた、xmlでonClickを書いとくのを。

android:onClick="onClickStart"
android:onClick="onClickStop"
android:onClick="onClickSkip"

を、それぞれxmlに追加。
で、SDMediaPlayerのimplements View.OnClickListener削除。
フィールドの

    private Button btnStart;
    private Button btnStop;
    private Button btnSkip;

も、削除。さらに、onCreate内の

        //ボタンの取得
        btnStart = (Button)findViewById(R.id.start_button);
        btnStop = (Button)findViewById(R.id.stop_button);
        btnSkip = (Button)findViewById(R.id.skip_button);
       
        //OnClickListenerのセット
        btnStart.setOnClickListener(this);
        btnStop.setOnClickListener(this);
        btnSkip.setOnClickListener(this);

も削除。で、onClickも削除して、

    //ボタンが押されたときの処理
    public void onClickStart(View view) {
       
        musicNum = musicPlayer.getMusicNum();
       
        if (musicPlayer.isPlaying()) {
            if (++musicNum < musicList.size()) {
               
                musicPlayer.setMusicNum(musicNum);
                musicPlayer.playMusic();
            } else {
               
                musicPlayer.setMusicNum(0);
                musicPlayer.playMusic();
            }
        } else {
            musicPlayer.playMusic();
        }
    }
   
    public void onClickStop(View view) {
        if(musicPlayer.isPlaying()) musicPlayer.stop();
    }
   
    public void onClickSkip(View view) {
        if(musicPlayer.isPlaying()) musicPlayer.skipMusic();
    }

に、変更。ボタン一個一個ばらばら。良いのか悪いのか。
まあ、とりあえず。

一度作ったとはいえ、行き当たりばったりは変わらず。
ふらふら、ふらふら。

後、結構重要な事を書くのを忘れてました。
Android Manifestのactivityのとこを、

        <activity android:name=".SDMediaPlayerActivity"
                  android:label="@string/app_name"
                  android:screenOrientation="portrait"
                  android:configChanges="orientation|keyboardHidden">

こんな感じに、下2行追加しておくと、縦画面固定で
横にしても音楽が、かかりっぱなしの暴走をしなくなります。
ここに 書いてました。わたくし、is01なので、keyboardHiddenをつけてます。

これは、もう少し見つけやすいとこに書いといた方が良かったかも。
次回の先頭につけときます。

ただ、他で見たときは、お勧めしない見たいなことが書いてあったような気が。
 まあ、ね。

次回は、大きく変更予定。主に、見た目を。

2010-11-26

mediaplayerを作ってみる(4)

今回の変更は、SDのディレクトリから音楽ファイルを読み込むように
してみました。といっても、1個のディレクトリからですが。

とりあえず、フィールドにこんなのを↓追加

    private static final String SD_PATH = //SDのパス
        Environment.getExternalStorageDirectory().getPath();

    private static final String FILE_SEP = File.separator;//pathの区切り文字

まあ、何となく。やってみました。
 で、用意したディレクトリがdeepfm。これを使って

        //musicListの生成と曲の追加
        musicList = new ArrayList<String>();

        File musicFile = new File(SD_PATH + FILE_SEP + "deepfm");
        String[] musicFileList = musicFile.list();
       
        for(String fileName : musicFileList) {
            File f = new File(SD_PATH + FILE_SEP + "deepfm"
                    + FILE_SEP + fileName);
            if(f.isFile() && fileName.endsWith("mp3"))
                musicList.add(fileName);
        }


んな感じ。MusicPlayerの方もちょっと変更。フィールドに

    private static final String SD_PATH = //SDのパス
        Environment.getExternalStorageDirectory().getPath();

    private static final String FILE_SEP = File.separator;//pathの区切り文字

同じ物を追加。static final。なんか響きが気に入ってて。
で、mediaPlayerに曲のパスをセットするとこを

mediaPlayer.setDataSource(SD_PATH + FILE_SEP + "deepfm"
                    + FILE_SEP + musicList.get(musicNum));

それだけ。次もまた、地味に変更予定。

2010-11-25

mediaplayerを作ってみる(3)

前回のまま続けると、また同じ事になりそうなので新しくclassを作って分離。
MusicPlayer class。見たままです。貼っときます。

package net.asasvata.sdmediaplayer;

import java.util.ArrayList;

import android.media.MediaPlayer;
import android.os.Environment;

public class MusicPlayer extends MediaPlayer
                implements MediaPlayer.OnCompletionListener {
   
    private MediaPlayer mediaPlayer;
    private ArrayList<String> musicList;
    private int musicNum;
   
    public MusicPlayer(ArrayList<String> list) {
       
        this.musicList = list;
        musicNum = 0;
       
        //mediaPlayerの生成と曲が終わったときの処理の準備
        mediaPlayer = new MediaPlayer();
        mediaPlayer.setOnCompletionListener(this);
    }
   
    public int getMusicNum() {
        return musicNum;
    }
   
    public void setMusicNum(int num) {
        musicNum = num;
    }
   
    //音楽ファイルのパスを取得してスタート。
    public void playMusic() {
       
        mediaPlayer.reset();//これが要る様だ。
       
        try{
            mediaPlayer.setDataSource(Environment.getExternalStorageDirectory().getPath()
                    + "/" + musicList.get(musicNum));
           
            mediaPlayer.prepare();
            mediaPlayer.seekTo(0);
            mediaPlayer.start();
           
        } catch (Exception e) {
            System.exit(-1);
        }
    }
   
    public void stopMusic() {
       
        mediaPlayer.stop();
       
        try {
               mediaPlayer.prepare();
              
        } catch (Exception e) {
            System.exit(-1);
        }
    }
   
    //残り3秒まで飛びます。
    public void skipMusic() {
       
        int duration = mediaPlayer.getDuration();
        mediaPlayer.seekTo(duration - 3000);
    }
   
    //getterを作ってもいいんですが、何となく。
    public boolean isPlayMusic() {
       
        return mediaPlayer.isPlaying();
    }
   
    //曲が終わったときの処理
    public void onCompletion(MediaPlayer mp) {
        if (++musicNum < musicList.size()) {
           
            playMusic();
           
        } else {
           
            musicNum = 0;
            playMusic();
        }   
    }
}



SDMediaPlayerActivityの方は
//mpの生成以下の3行削除で、

  //musicPlayerの生成とmusicNumの取得
  musicPlayer = new MusicPlayer(musicList);
  musicNum = musicPlayer.getMusicNum();

↑を追加。後は、onClickを

public void onClick(View view) {
      
        musicNum = musicPlayer.getMusicNum();
      
        if (musicPlayer.isPlayMusic()) {
          
            if (view == btnStart) {
                if (++musicNum < musicList.size()) {
                  
                    musicPlayer.setMusicNum(musicNum);
                    musicPlayer.playMusic();
                } else {
                  
                    musicPlayer.setMusicNum(0);
                    musicPlayer.playMusic();
                }
            }
            else if (view == btnStop) musicPlayer.stopMusic();
          
            else if (view == btnSkip) musicPlayer.skipMusic();
      
        } else {
            if (view == btnStart) musicPlayer.playMusic();
        }
    }

んな感じに変更。 動きに変化はありません。が、何となくすっきり。
したと思いたい。

次は、またちょっとだけ変更予定。

2010-11-24

mediaplayerを作ってみる(2)

そういえば、一応目標を。と言うか、理想の完成形を。

1・・・SDカードのいくつかのディレクトリから音楽ファイルを読み込む。
2・・・ListViewに表示する。
3・・・ListViewをタッチすると音楽が聴ける。
4・・・ディレクトリ内で連続再生 。
5・・・ディレクトリをまたいで連続再生。
6・・・ランダム再生。

こんな感じ。

前回のでは、曲が終わると止まってしまう。
まず、これを何とかしようと。ここなどを参考に。(ちょっと下の方)

OnCompletionListenerとやらで、何とかなりそう。
 変更点だけ書いていきます。

フィールドの
private static int num = 0; を private int musicNum; に
なんかこの方が良さそうなので。

implementsに MediaPlayer.OnCompletionListener を追加。

//mpの生成 のとこを

mp = new MediaPlayer();
mp.setOnCompletionListener(this); //ここと
musicNum = 0; //ここを追加

で、一番下に

     public void onCompletion(MediaPlayer mp) {
        if (++musicNum < musicList.size()) playMusic();
        else {
            musicNum = 0;
            playMusic();
        } 
    }

を追加。
で、このままだと1曲終わるまで動きが確認できないのでボタンを1つ追加。

    <Button
        android:id="@+id/skip_button"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/skip_button">
    </Button>

ボタンのテキストをstringに追加。

    <string name="skip_button">skip</string>

なんか英語。あってるんだろうか。英語力がないのが残念。

で、↓を追加。他のボタンの下あたりに適当に。

btnSkip = (Button)findViewById(R.id.skip_button);
btnSkip.setOnClickListener(this);

この書き方でなく、ここを参考にして書き直したほうがいいかも。
僕は、まあ、そのうち。

それと、ボタンイベントを追加。btnStopの次に。(else ifの { の閉じた後)

} else if (view == btnSkip) {
                int duration = mp.getDuration();
                mp.seekTo(duration - 3000);
}

 これで、残り3秒まで飛びます。続けて再生してるか確認しやすい。
最近気づきました。

実は一度、完成形間近まで作ったんですが、コードが読みにくいし、
ちょっと行き詰まったので、ここに書きながら作り直してます。

まあ、それはそれで動いてるんですが。あまり色々操作をしなければ。
例の8円運用 is01に 取り込んでみて、今もそれで音楽を聴いてます。

でもねー、なんかねー、と言う感じなんですわ。色々と。
なので、あせらず急がず。ちょとづつ。なるべく、読みやすく。

いつか、完成するんだろうか。しないかも。
まあ、それはそれで。

2010-11-22

mediaplayerを作ってみる(1)

SDカードのファイルを再生する

作っています。少しづつ。まあ、どこまでいけるか分かりませんが。
とりあえず、貼っときます。

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">
    <Button
        android:id="@+id/start_button"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/start_button">
    </Button>
    <Button
        android:id="@+id/stop_button"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/stop_button">
    </Button>
</LinearLayout>

ボタンが二つだけ。一応string.xmlも使ってみました。

 <?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, SDMediaPlayerActivity!</string>
    <string name="app_name">SDMP</string>
    <string name="start_button">再生 / 次へ</string>
    <string name="stop_button">停止</string>
</resources>

 HelloWorld消すの忘れてました。

 で、Activity。

package net.asasvata.sdmediaplayer;

import java.util.ArrayList;

import android.app.Activity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;

public class SDMediaPlayerActivity extends Activity
    implements View.OnClickListener {
   
    //フィールド
    private static int num = 0;//次の曲に進む用

    private MediaPlayer mp;
   
    private ArrayList<String> musicList;
   
    private Button btnStart;
    private Button btnStop;
       
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        //mpの生成
        mp = new MediaPlayer();
       
        //musicListの生成と曲の追加
        musicList = new ArrayList<String>();
        musicList.add("leavetheworldbehind.mp3");
        musicList.add("onlygirl.mp3");
        musicList.add("richgirl.mp3");
        musicList.add("rudeboy.mp3");
        musicList.add("yeahyeah.mp3");
       
        //ボタンの取得
        btnStart = (Button)findViewById(R.id.start_button);
        btnStop = (Button)findViewById(R.id.stop_button);
       
        //OnClickListenerのセット
        btnStart.setOnClickListener(this);
        btnStop.setOnClickListener(this);
    }
    //ボタンが押されたときの処理
    public void onClick(View view) {
        if (mp.isPlaying()) {
            if (view == btnStart) {
                if (++num < musicList.size()) {
                   
                    playMusic();
               
                } else {
                    num = 0;
                    playMusic();
                }
            } else if (view == btnStop) {
                mp.stop();
                try {
                    mp.prepare();
                } catch (Exception e){
                }
            }
        } else {
            if (view == btnStart) {
               
                playMusic();
            }
        }
    }
   
    public void playMusic() {
        mp.reset();
        try{
            mp.setDataSource(Environment.getExternalStorageDirectory().getPath()
                    + "/" + musicList.get(num));
            mp.prepare();
            mp.seekTo(0);
            mp.start();
        } catch (Exception e) {
        }
    }
}

Environment.getExternalStorageDirectory().getPath()
↑で、SDのパスが得られるようです。"/sdcard"でもいける様ですが。
こっちの方が確実みたいなので。

ボタンを押したときの動きは見たままです。
とりあえず、sdの音楽は再生できます。
エミュレーターのsdにファイルを入れるやり方はここを参考に。
sdのパスの取りかたも。

なんか疲れました。

2010-11-20

自作Viewをレイアウトに追加

seesaaから、移動。

自作Viewの貼り付けについては、ここを参考に。
で、本に乗ってたのを改造したのを。長いですが。

SurfaceViewなんですが、ここを見ると一手間要るようです。
が、なぜか動きます。Viewと同じやり方で。何かの参考になればいいですが。

 とりあえず、xmlから。色とか文字はstring.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"
    >
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#00000000"
        >
           <ImageView
            android:id="@+id/imageView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
        />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#00c608"
            android:textSize="12sp"
            android:text="適当にボタンを押してください\n数字はフォントサイズです"
            android:layout_weight="2"
        />
    </LinearLayout>
    <net.asasvata.SampleSurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1"
    />
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#00000000"
        >
        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="start"
        />
        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="stop"
        />
    </LinearLayout>
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#00000000"
        >
        <RadioGroup
            android:id="@+id/radioGroup"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_weight="1"
            >
            <RadioButton
                android:id="@+id/radioButton0"
                android:text="H"
                android:textColor="#00c608"
               />
             <RadioButton
                android:id="@+id/radioButton1"
                android:text="M"
                android:textColor="#00c608"
               />
               <RadioButton
                android:id="@+id/radioButton2"
                android:text="L"
                android:textColor="#00c608"
               />
        </RadioGroup>
    </LinearLayout>
</LinearLayout>

パッケージ名とファイル名を指定。あとは同じようなやり方。
次は、SurfaceViewを。

package net.asasvata;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet; //これが重要みたいです。
import android.view.*;
//サーフェイスビューの利用
public class SampleSurfaceView extends SurfaceView     
           implements   SurfaceHolder.Callback,Runnable {

 private SurfaceHolder holder;//サーフェイスホルダー
    private Thread thread;        //スレッド

    private int px = 0;//X座標
    private int py = 5;//Y座標
    private int vx = 0;//X速度
    private int vy = 0;//Y座標
    //コンストラクタ
    public SampleSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //サーフェイスホルダーの生成
        holder = getHolder();
        holder.addCallback(this);
        holder.setFixedSize(getWidth(), getHeight());
    }
    //フィールドをprivateにしてみたので、ゲッター&セッター
    public int getVx() {
        return vx;
    }
    public int getVy() {
        return vy;
    }
    public void setVx(int vx) {
        this.vx = vx;
    }
    public void setVy(int vy) {
        this.vy = vy;
    }
    //サーフェイスの生成
    public void surfaceCreated(SurfaceHolder holder) {
        
        //スレッドの開始
        thread = new Thread(this);
        thread.start();
    }
    //サーフェイスの変更
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    }
    //サーフェイスの破棄
    public void surfaceDestroyed(SurfaceHolder holder) {
        thread = null;
    }
    //スレッドの処理
    public void run() {
        int i = 5;

        Paint paint = new Paint();
        paint.setTextSize(i);
        Canvas canvas;
        int j=0, k=0, l = 0;

        while(thread != null) {
            //ダブルバッファリング
            String str = ""+i;
            paint.setTextSize(i);
            paint.setColor(Color.rgb(255-j, 255-k, 255-l));
            canvas = holder.lockCanvas();
            canvas.drawColor(Color.argb(255, j, k, l));
            canvas.drawText(str, px, py, paint);
            holder.unlockCanvasAndPost(canvas);
            //移動
            if (vx > 0) {
                //文字サイズに合わせて跳ね返る位置を調整
                if (getWidth()-paint.measureText(str)< px){
                    vx = -vx;
                    i += 5; j += 10; k += 20; l += 30;
                    if (i > 101) i = 5;
                    if (j > 255) j = 0;
                    if (k > 255) k = 0;
                    if (l > 255) l = 0;
                }
            } else {
                if (px < 0) {
                    vx = -vx;
                    i += 5; j += 10; k += 20; l += 30;
                    if (i > 101) i = 5;
                    if (j > 255) j = 0;
                    if (k > 255) k = 0;
                    if (l > 255) l = 0;
                }
            }
            if (vy < 0) {
                //フォントサイズに合わせて跳ね返る位置を調整・・・のはずなんですが。
                if (py < i) vy = -vy;
            } else {
                if (getHeight()< py) vy = -vy;
            }
            px += vx;
            py += vy;
            //スリープ
            try {
                Thread.sleep(50);
            } catch (Exception e) {
            }
        }
    }
}

次は、Activity。

 package net.asasvata;

import android.app.Activity;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RadioGroup;

//サーフェイスビュー、テキストビュー、ボタン、ラジオボタンを使います
public class SampleActivity extends Activity implements View.OnClickListener {
   
    SampleSurfaceView sv;
    private Button button1, button2;
    private RadioGroup radioGroup;
  
    int num = 1;//ボタンを押したときの状態保持のために使います
    int sp = 0;//移動速度を変更するために使います
  
    //アプリの初期化
    @Override
    public void onCreate(Bundle icicle) {      
        super.onCreate(icicle);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.main);
      
        ImageView imageView = (ImageView)findViewById(R.id.imageView);
        imageView.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.icon));
      
        sv = (SampleSurfaceView)findViewById(R.id.surfaceView);
      
        button1 = (Button)findViewById(R.id.button1);
        button1.setOnClickListener(this);
      
        button2 = (Button)findViewById(R.id.button2);
        button2.setOnClickListener(this);
      
        radioGroup =(RadioGroup)findViewById(R.id.radioGroup);
        radioGroup.check(R.id.radioButton1);
    }
  
    //ボタンとラジオボタンがクリックされたときの処理
    public void onClick(View view) {
      
        //ラジオボタンが押されたときの処理
        switch (radioGroup.getCheckedRadioButtonId()) {
        //ラジオボタンのidによって処理を変えます
        case R.id.radioButton0:
            sp = 14;
            //ラジオボタンが押されたときの速度方向を維持します
            keepSpDir(sv);
            break;
        case R.id.radioButton1:
            sp = 7;
            keepSpDir(sv);
            break;
        case R.id.radioButton2:
            sp = 3;
            keepSpDir(sv);
            break;
        }
      
        //ボタンがクリックされたときの処理
        if (view == button1) {
            //button1が連続して押されたとき何もしないようにしてます
            if (num == 0) {
            } else {
                //button2が押されたときのnumの値で処理を変えます
                switch (num) {
                case 1:
                    //速度方向の維持
                    sv.setVx(sp); sv.setVy(sp);
                    num = 0;//これで連続して押されたときの処理につなげます
                    break;
                case 2:
                    sv.setVx(-sp); sv.setVy(sp);
                    num = 0;
                    break;
                case 3:
                    sv.setVx(sp); sv.setVy(-sp);
                    num = 0;
                    break;
                case 4:
                    sv.setVx(-sp); sv.setVy(-sp);
                    num = 0;
                    break;
                }
            }
        } else if (view == button2) {
            //button2が押された時点での速度方向によってnumの値を変えます
            if (sv.getVx()>0 && sv.getVy()>0) {
                sv.setVx(0); sv.setVy(0);
                num = 1;
            } else if (sv.getVx()<0 && sv.getVy() >0) {
                sv.setVx(0); sv.setVy(0);
                num = 2;
            } else if (sv.getVx()>0 && sv.getVy() <0) {
                sv.setVx(0); sv.setVy(0);
                num = 3;
            } else if (sv.getVx()<0 && sv.getVy()<0) {
                sv.setVx(0); sv.setVy(0);
                num = 4;
            }
        }
    }
  
    private void keepSpDir(SampleSurfaceView sv) {
      
        if (sv.getVx()>0 && sv.getVy()>0) {
            sv.setVx(sp); sv.setVy(sp);
        } else if (sv.getVx()<0 && sv.getVy() >0) {
            sv.setVx(-sp); sv.setVy(sp);
        } else if (sv.getVx()>0 && sv.getVy() <0) {
            sv.setVx(sp); sv.setVy(-sp);
        } else if (sv.getVx()<0 && sv.getVy()<0) {
            sv.setVx(-sp); sv.setVy(-sp);
        } else {
            sv.setVx(sp); sv.setVy(sp);
        }
    }
}

 なんかよく分からないままに改造したんで、おかしなとこもあるかも。
まあ、だいたいで。

ここだと、貼り付けたときもインデントが残る・・・。
初めからここで書いとけばよかった。