エンジニア未満がエンジニア以上を目指す日々(仮)

戦力外通告の悔しさをバネに自身の技術力向上を目指した技術ブログ

ファイル選択機能の追加 - 壁紙変更アプリ (9)

今までは画像選択をスクリーンショットのディレクトリ固定にしていました。
今回は別のディレクトに移動できるようにしてみます。
と言いつつ、今回は時間の都合で残念実装。

初期位置を変更しました。

        //files = new File("/storage/sdcard0/Pictures/Screenshots").listFiles();
        files = new File("/storage/sdcard0/").listFiles();

onItemClick を修正して、ディレクトリの場合はリストを再作成して、
onItemClick を抜けます。

            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                String click_parent = (String) parent.getClass().getSimpleName();
                String click_position = String.valueOf(position);
                String click_id = String.valueOf(id);

                Log.v(TAG, String.format("onItemClick click_parent   : %s", click_parent));
                Log.v(TAG, String.format("onItemClick click_position : %s", click_position));
                Log.v(TAG, String.format("onItemClick click_id       : %s", click_id));

                if(files[position].isDirectory() == true) {
                    item_list.clear();
                    files = new File(files[position].toString()).listFiles();
                    if (files != null) {
                        for (int i = 0; i < files.length; i++) {
                            item_list.add(files[i].getName());
                        }
                    }
                    ArrayAdapter<String> arrayadapter = new ArrayAdapter<String>
                            (SubActivity.this, android.R.layout.simple_expandable_list_item_1, item_list);
                    listview.setAdapter(arrayadapter);
                } else if(files != null) {
                    // Implementation for changing the wallpaper
                    // 今までと同じ

これで、ディレクトリを掘り進めながら画像ファイルを選択できます。
てか、実装見れば一目瞭然ですが、残念実装の以下二点。

  • ほんとに掘り進むだけで上に上がれません
  • スクリーンショット以外を選択出来る様になったので、画像ファイル以外を選択出来て死にます

もうちょっと何とかします。

明示的 intent による画面遷移 - 壁紙変更アプリ (8)

壁紙変更アプリの現仕様は "Choose" ボタン押下で、
スクリーンショットのファイルリストを List View で表示し、
設定する壁紙を選択するようにしています。

ですが、同一 Activity 内で List View を表示しているため、
List View 表示時に Back でいきなりアプリが終了という残念挙動。
あと、選択後に List View を消す方法も分からなかったため、
選択で壁紙は変更されるけど、List View は出っぱなしという、
これまた残念挙動でした。

そこで、List View 表示の Activity を分けることで、
Activity の遷移により、Back や選択後の画面遷移を制御します。

参考にしたのは以下のサイトです。
Androidでの画面遷移方法、Intentの使い方 | Tech Booster
画面を遷移する - Androidプログラマへの道 〜 Moonlight 明日香 〜

まずは、新しい Activity である SubActivity を追加します。

AndroidManifest.xml

        <activity
            android:name="SubActivity"
            android:label="Wallpaper changer">
        </activity>

で、AndroidStudio 上で新規ファイルの SubActivity.java を追加します。
MainActivity.java あたりで右クリックして New -> Java Class を選択。

f:id:hielf:20140712213349p:plain:w400

Create New Class のダイアログが出てくるので、
Name に SubActivity を指定して、Kind は Class を指定します。

f:id:hielf:20140712214012p:plain:w400

ちなみに、最初 Name に SubActivity.java を指定すると、
ディレクトリが掘られて意図した通りになりませんでした。。
あくまで Create New Class だからなのかな?

次に明示的 intent による Activity の遷移を実装します。
今回 SubActivity に分けるのは、List View の表示です。

layout/activity_main.xml で Button と ListView を定義していましたが、
ListView を activity_main.xml から、activity_sub.sml に移動します。

activity_sub.xml

    <ListView android:id="@+id/listview"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#ffffffff" />

次に、明示的 intent による Activity の遷移を実装します。
今まで "Choose" ボタンクリックでリストを作成していた実装を
先ほど追加した SubActivity.java に丸ごと移動します。
その代わりに SubActivity へ intent を投げるようにします。

MainActivity.java

            case R.id.Button_Choose:
                Intent intent = new Intent(MainActivity.this, SubActivity.class);
                startActivity(intent);

リスト作成の実装を SubActivity.java に丸ごと移動して適宜修正しています。
あと、リスト選択後に finish() で遷移後の Activity を終了して、
元の Activity に戻るようにしました。

SubActivity.java

public class SubActivity extends ActionBarActivity{

    private static final String TAG = "WallpaperChange";
    WallpaperManager mWM;
    Bitmap bmpImageFile;

    private ArrayList<String> item_list;
    private String strPath;
    private File[] files;
    private ListView listview;
    private String item;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sub);

        mWM = WallpaperManager.getInstance(this);

        listview = (ListView) findViewById(R.id.listview);
        item_list = new ArrayList<String>();

        // Hard-coded files position.
        files = new File("/storage/sdcard0/Pictures/Screenshots").listFiles();

        // Get files list
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                item_list.add(files[i].getName());
            }
        }
        ArrayAdapter<String> arrayadapter = new ArrayAdapter<String>
                (SubActivity.this, android.R.layout.simple_expandable_list_item_1, item_list);
        listview.setAdapter(arrayadapter);
        listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                String click_parent = (String) parent.getClass().getSimpleName();
                String click_position = String.valueOf(position);
                String click_id = String.valueOf(id);

                Log.v(TAG, String.format("onItemClick click_parent   : %s", click_parent));
                Log.v(TAG, String.format("onItemClick click_position : %s", click_position));
                Log.v(TAG, String.format("onItemClick click_id       : %s", click_id));

                // Implementation for changing the wallpaper
                Log.v(TAG, "onItemClick:" + files[position].toString());
                bmpImageFile = BitmapFactory.decodeFile(files[position].toString());

                int height = mWM.getDesiredMinimumHeight();
                int width = mWM.getDesiredMinimumWidth();

                Log.v(TAG, "before height:" + height);
                Log.v(TAG, "before width:" + width);

                //Bitmap resizeBmp = Bitmap.createScaledBitmap(bmpImageFile, 1920, 1200, true);
                try {
                    mWM.setBitmap(bmpImageFile);
                    //mWM.setBitmap(resizeBmp);
                    mWM.suggestDesiredDimensions(1200, 1920);

                    height = mWM.getDesiredMinimumHeight();
                    width = mWM.getDesiredMinimumWidth();

                    Log.v(TAG, "after height:" + height);
                    Log.v(TAG, "after width:" + width);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                finish();
            }
        });
    }
}

これで、List View のファイル選択時に Back でボタン選択画面に戻れるし、
壁紙選択後にもボタン選択画面に戻れるようになりました。
少しまともなアプリっぽくなってきた?

ボタン選択画面
f:id:hielf:20140712213150p:plain:w300

スクリーンショットのファイルリスト選択画面
f:id:hielf:20140712213152p:plain:w300

壁紙設定後の Home 画面
f:id:hielf:20140712213155p:plain:w300

次はスクリーンショット以外のファイルを選択出来るようにする予定です。

Nexus7 Android L へのアップデート

Android L へアップデートしてみます。

公式のページはこちら。
Setting Up the Preview SDK | Android Developers

で、Nexus7 2013 Wifi 用のファクトリーイメージをダウンロードするためには、
Install the L Preview System Image の razor-lpv79-preview-d0ddf8ce.tgz をクリックします。

Android L preview 版のファクトリーイメージのダウンロードにはライセンスの許諾が必要になります。
他のファクトリーイメージでは聞かれなかったよね?
内容をどこかで詳しく解説してないかなぁ。

書き換え手順はいつも通りで。
Factory Images for Nexus Devices - Android — Google Developers

$ tar xvf razor-lpv79-preview-d0ddf8ce.tgz
$ cd razor-lpv79

ん、なんか Nexus7 に adb がつながらない?
あぁ先日に 4.4.4 に書き換えたあと何もしてなかった。。

設定 -> タブレット情報 で、ビルド番号を7回タップする。
すると設定に開発者向けオプションが出てくるので、
ここで USB デバッグを許可する。

気を取り直して。

$ adb reboot bootloader
$ ./flash-all.sh

後はこんがり焼きあがったら出来上がり。
なお、Android L も開発者向けオプションの出し方は 4.4 系と同じでした。

Nexus7 4.4.4 アップデート

また風邪ひいた。。。
前よりひどいので、一日寝っぱなし。

気付いたら Nexus7 4.4.4 のファクトリーイメージが出てたので、
書き換えてみました。

手順はここ。
Factory Images for Nexus Devices - Android — Google Developers

ファームはここ。

差分は見てないけど、多分 OpenSSL 絡みの修正なんだろうなぁ。
Android L への書き換えはまた今度。

クリック処理を匿名クラスから OnClickListener インターフェースの実装に変更 - 壁紙変更アプリ (7)

画面遷移は新しいアクティビティを作成して制御すれば良いらしい。
新しいアクティビティを作成しない方法もあるみたいだけど、
今回は素直に新しいアクティビティを作成してみます。

ですが、その前にリファクタリングとして、クリック処理を、
匿名クラスから OnClickListener インターフェースの実装に変更します。

まずは主な修正のみ抜粋。

OnClickListener インターフェースを実装。

-public class MainActivity extends ActionBarActivity {
+public class MainActivity extends ActionBarActivity implements OnClickListener{

匿名クラスを切り出し。

         button = (Button) findViewById(R.id.Button_Choose);
-        button.setOnClickListener(new OnClickListener() {
+        button.setOnClickListener(this);
...
+    public void onClick(View v) {

今まで各ボタンに匿名クラスの形だったので、
onClick で識別。

+    public void onClick(View v) {
+        switch(v.getId()) {
+            case R.id.Button_Choose:

あとの中身はほぼ同じで、リファクタリング終了。
全体としてはこんな感じになりました。
まえのコードとかログとか残ってて汚いですが…。
なお、OnItemClickListener は1つのボタンのみなので、
そのまま匿名クラスです。

public class MainActivity extends ActionBarActivity implements OnClickListener{

    private static final String TAG = "WallpaperChange";
    WallpaperManager mWM;
    Bitmap bmpImageFile;

    private ArrayList<String> item_list;
    private String strPath;
    private File[] files;
    private ListView listview;
    private String item;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button;
        button = (Button) findViewById(R.id.Button_Choose);
        button.setOnClickListener(this);
        button = (Button) findViewById(R.id.Button_Set);
        button.setOnClickListener(this);
        button = (Button) findViewById(R.id.Button_Clear);
        button.setOnClickListener(this);

        mWM = WallpaperManager.getInstance(this);

        int height = mWM.getDesiredMinimumHeight();
        int width = mWM.getDesiredMinimumWidth();

        Log.v(TAG, "Initial height = " + height);
        Log.v(TAG, "Initial width  = " + width);
    }

    public void onClick(View v) {
        switch(v.getId()) {
            case R.id.Button_Choose:
                Log.v(TAG, "Choose");
                listview = (ListView) findViewById(R.id.listview);
                item_list = new ArrayList<String>();

                // Hard-coded files position.
                files = new File("/storage/sdcard0/Pictures/Screenshots").listFiles();

                // Get files list
                if (files != null) {
                    for (int i = 0; i < files.length; i++) {
                        item_list.add(files[i].getName());
                    }
                }
                ArrayAdapter<String> arrayadapter = new ArrayAdapter<String>
                        (MainActivity.this, android.R.layout.simple_expandable_list_item_1, item_list);
                listview.setAdapter(arrayadapter);
                listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                        String click_parent = (String) parent.getClass().getSimpleName();
                        String click_position = String.valueOf(position);
                        String click_id = String.valueOf(id);

                        Log.v(TAG, String.format("onItemClick click_parent   : %s", click_parent));
                        Log.v(TAG, String.format("onItemClick click_position : %s", click_position));
                        Log.v(TAG, String.format("onItemClick click_id       : %s", click_id));

                        // Implementation for changing the wallpaper
                        Log.v(TAG, "onItemClick:" + files[position].toString());
                        bmpImageFile = BitmapFactory.decodeFile(files[position].toString());

                        int height = mWM.getDesiredMinimumHeight();
                        int width = mWM.getDesiredMinimumWidth();

                        Log.v(TAG, "before height:" + height);
                        Log.v(TAG, "before width:" + width);

                        try {
                            mWM.setBitmap(bmpImageFile);
                            mWM.suggestDesiredDimensions(1200, 1920);

                            height = mWM.getDesiredMinimumHeight();
                            width = mWM.getDesiredMinimumWidth();

                            Log.v(TAG, "after height:" + height);
                            Log.v(TAG, "after width:" + width);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        finish();
                    }
                });
                break;
            case R.id.Button_Set:
                try {
                    mWM.setResource(R.drawable.sample);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            case R.id.Button_Clear:
                Log.v(TAG, "Clear");
                try {
                    mWM.clear();

                    int height = mWM.getDesiredMinimumHeight();
                    int width = mWM.getDesiredMinimumWidth();

                    Log.v(TAG, "clear height:" + height);
                    Log.v(TAG, "clear width:" + width);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
        }
    }
}