com.mine.psf.PsfFileBrowserActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.mine.psf.PsfFileBrowserActivity.java

Source

/*************************************************************************
 * MinePsfPlayer is an Android App that plays psf and minipsf files.
 * Copyright (C) 2010-2012  Lei YU
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ************************************************************************/

package com.mine.psf;

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.text.method.LinkMovementMethod;
import android.text.util.Linkify;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.mine.psf.PsfFileNavigationUtils.PsfListAdapter;
import com.mine.psf.PsfUtils.ServiceToken;
import com.mine.psfplayer.R;

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

public class PsfFileBrowserActivity extends Activity implements ServiceConnection,
        SharedPreferences.OnSharedPreferenceChangeListener, ActivityCompat.OnRequestPermissionsResultCallback {
    private static final String LOGTAG = "PsfFileBrowserActivity";

    private static final int ID_EXIT = 1;
    private static final int ID_PLAY_ALL = 2;
    private static final int ID_SHUFFLE_ALL = 3;
    private static final int ID_SETTINGS = 4;
    private static final int ID_ABOUT = 5;

    private Context c;
    private ListView MusicListView;
    private PsfListAdapter MusicListAdapter;
    private ServiceToken mToken;
    private ArrayList<String> playList;
    private TextView CurDirView;
    private int focusListPosition = -1;
    private int mStepsBack; // handle BACK key press, up one level dir instead of exit the activity

    private final Handler handler = new Handler();

    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        c = this;

        checkStoragePermission();
        mToken = PsfUtils.bindToService(this, this);

        mStepsBack = 0;
        setContentView(R.layout.psffile_browser_activity);
        // Prepare the music list
        MusicListView = (ListView) findViewById(R.id.psffilelist);
        CurDirView = (TextView) findViewById(R.id.directory_text);

        Intent intent = getIntent();
        if (intent.getAction() == Intent.ACTION_VIEW) {
            String fullPath = intent.getData().getPath();
            if (fullPath.endsWith(".zip") || fullPath.endsWith(".ZIP")) {
                // Open a zip file, just browse into it
                browseToDir(fullPath);
            } else {
                String fileName = intent.getData().getLastPathSegment();
                String path = fullPath.substring(0, fullPath.lastIndexOf(fileName));

                browseToDir(path);
                String[] list = (String[]) playList.toArray(new String[playList.size()]);
                int i;
                for (i = 0; i < list.length; ++i) {
                    if (fullPath.equals(list[i])) {
                        final String[] threadList = list;
                        final int threadIndex = i;
                        focusListPosition = i;
                        final Runnable playRunnable = new Runnable() {
                            @Override
                            public void run() {
                                if (!PsfUtils.isServiceConnected()) {
                                    // Wait until the service is connected
                                    handler.postDelayed(this, 50);
                                    return;
                                }
                                PsfUtils.playAll(threadList, threadIndex);
                                startActivity(new Intent(getApplicationContext(), PsfPlaybackActivity.class));
                            }
                        };
                        handler.postDelayed(playRunnable, 50);
                        break;
                    }
                }
                if (i == list.length) {
                    Log.e(LOGTAG, "Failed to get the file: " + fileName);
                }
            }
        } else {
            handleFirstTimeRun();
            Bundle extras = intent.getExtras();
            if (extras != null && extras.containsKey(getString(R.string.extra_current_list_position))) {
                // If extras contains current list pos,
                // we should focus on the item after connected to the service
                focusListPosition = extras.getInt(getString(R.string.extra_current_list_position));
            } else {
                showFiles();
            }
        }

        MusicListView.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                // When clicked, start playing
                String filePath = MusicListAdapter.getFilePath(position);
                int fileType = PsfFileNavigationUtils.GetFileType(filePath);

                if (fileType == PsfFileNavigationUtils.PsfFileType.TYPE_DIR
                        || fileType == PsfFileNavigationUtils.PsfFileType.TYPE_ZIP) {
                    Log.d(LOGTAG, "pick a directory: " + filePath);
                    // Check the if it's go up or down level of dir
                    String curDir = MusicListAdapter.getCurDir();
                    if (filePath.compareTo(curDir) < 0) {
                        // up one level
                        mStepsBack--;
                        //Log.d(LOGTAG, "up one level: " + mStepsBack);
                    } else {
                        // down one level
                        mStepsBack++;
                        //Log.d(LOGTAG, "down one level: " + mStepsBack);
                    }
                    browseToDir(filePath);
                } else {
                    Log.d(LOGTAG, "pick a music: " + filePath + " at pos " + position);
                    String[] list = (String[]) playList.toArray(new String[playList.size()]);
                    // Play the file in the list
                    PsfUtils.playAll(list, position - MusicListAdapter.getNumberDirs());
                    //PsfUtils.play(view.getContext(), musicName);
                    startActivity(new Intent(view.getContext(), PsfPlaybackActivity.class));
                }
            }
        });

        // Register listener on psf root dir change
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        prefs.registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    public void onPause() {
        super.onPause();
    }

    @Override
    public void onStop() {
        super.onStop();
    }

    @Override
    public void onDestroy() {
        if (mToken != null) {
            PsfUtils.unbindFromService(mToken);
        }
        unregisterReceiverSafe(mTrackListener);
        super.onDestroy();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        menu.add(0, ID_PLAY_ALL, 0, R.string.play_all).setIcon(R.drawable.ic_menu_play_clip);
        menu.add(0, ID_SHUFFLE_ALL, 0, R.string.shuffle_all).setIcon(R.drawable.ic_menu_shuffle);
        menu.add(0, ID_SETTINGS, 0, R.string.settings).setIcon(R.drawable.ic_settings);
        menu.add(0, ID_ABOUT, 0, R.string.about).setIcon(R.drawable.ic_about);
        menu.add(0, ID_EXIT, 0, R.string.menu_exit).setIcon(R.drawable.ic_menu_exit);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case ID_EXIT:
            ExitApp();
            return true;
        case ID_PLAY_ALL: {
            String[] list = (String[]) playList.toArray(new String[playList.size()]);
            if (list.length == 0) {
                showListEmptyError();
                return true;
            }
            PsfUtils.playAll(list, 0);
            startActivity(new Intent(this, PsfPlaybackActivity.class));
            return true;
        }
        case ID_SHUFFLE_ALL: {
            String[] list = (String[]) playList.toArray(new String[playList.size()]);
            if (list.length == 0) {
                showListEmptyError();
                return true;
            }
            PsfUtils.shuffleAll(list);
            startActivity(new Intent(this, PsfPlaybackActivity.class));
            return true;
        }
        case ID_ABOUT: {
            showDialog(ID_ABOUT);
            break;
        }
        case ID_SETTINGS: {
            showSettings();
            break;
        }
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        // show dialog according to the id
        final String msg;
        if (id == ID_ABOUT) {
            // Get version code
            String versionString = "";
            PackageManager manager = getPackageManager();
            try {
                PackageInfo info = manager.getPackageInfo(getPackageName(), 0);
                versionString = info.versionName;
            } catch (NameNotFoundException e) {
                e.printStackTrace();
            }
            // Format dialog msg
            msg = String.format(getString(R.string.sexypsf_about), versionString);
        } else {
            Log.e(LOGTAG, "Unknown dialog id");
            msg = "";
        }

        final TextView msgView = new TextView(this);
        msgView.setText(msg);
        msgView.setAutoLinkMask(Linkify.ALL);
        msgView.setTextAppearance(this, android.R.style.TextAppearance_Medium);
        msgView.setMovementMethod(LinkMovementMethod.getInstance());

        return new AlertDialog.Builder(this).setView(msgView).setCancelable(true)
                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
                        /* User clicked OK so do some stuff */
                    }
                }).create();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (mStepsBack > 0) {
                upOneLevel();
                return true;
            }
        }

        return super.onKeyDown(keyCode, event);
    }

    private void ExitApp() {
        PsfUtils.quit();
        finish();
    }

    private void showSettings() {
        Intent intent = new Intent(this, PsfSettingsActivity.class);
        startActivity(intent);
    }

    private void showListEmptyError() {
        // Show a toast indicating play list empty
        Toast.makeText(this, R.string.playlist_empty_error, Toast.LENGTH_LONG).show();
    }

    private void showStoragePermissionReason() {
        Toast.makeText(this, R.string.permission_storage_reason, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.d(LOGTAG, "onServiceConnected");
        PsfUtils.updateNowPlaying(this);
        IntentFilter f = new IntentFilter();
        f.addAction(PsfPlaybackService.META_CHANGED);
        registerReceiver(mTrackListener, new IntentFilter(f));

        if (focusListPosition != -1) {
            PsfPlaybackService psfService = ((PsfPlaybackService.ServiceBinder) service).getService();

            String[] playList = psfService.getPlaylist();
            if (playList != null && focusListPosition >= 0 && focusListPosition < playList.length) {
                String mediaFile = playList[focusListPosition];
                String parentDir = PsfFileNavigationUtils.getParentDir(mediaFile);
                if (parentDir != null) {
                    //Log.d(LOGTAG, "Going to focus on " + mediaFile);
                    browseToDir(parentDir, focusListPosition);
                } else {
                    // Should never occur
                    Log.e(LOGTAG, "Media path incorrect: " + mediaFile);
                }
            } else {
                // Occurs if the playlist is changed out of sudden
                Log.e(LOGTAG, "To focused item incorrect!");
            }
            focusListPosition = -1;
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        Log.d(LOGTAG, "onServiceDisconnected");
        finish();
    }

    private BroadcastReceiver mTrackListener = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(PsfPlaybackService.META_CHANGED)) {
                PsfUtils.updateNowPlaying(PsfFileBrowserActivity.this);
            }
        }
    };

    /**
     * Unregister a receiver, but eat the exception that is thrown if the
     * receiver was never registered to begin with. This is a little easier
     * than keeping track of whether the receivers have actually been
     * registered by the time onDestroy() is called.
     */
    private void unregisterReceiverSafe(BroadcastReceiver receiver) {
        try {
            unregisterReceiver(receiver);
        } catch (IllegalArgumentException e) {
            // ignore
        }
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        if (key == getString(R.string.key_psf_root_dir)) {
            Log.d(LOGTAG, "psf root changed, refresh list...");
            mStepsBack = 0;
            browseToDir(PsfDirectoryChoosePreference.getPsfRootDir(c));
        }
    }

    private void browseToDir(String dir) {
        MusicListAdapter = PsfFileNavigationUtils.browseToDir(c, dir, PsfFileNavigationUtils.BROWSE_MODE_ALL);
        MusicListView.setAdapter(MusicListAdapter);
        playList = MusicListAdapter.getPlayList();
        CurDirView.setText(MusicListAdapter.getCurDir());
    }

    private void browseToDir(String dir, int focusPosition) {
        browseToDir(dir);
        focusPosition += MusicListAdapter.getNumberDirs();
        MusicListView.setSelection(focusPosition);
        //Log.d(LOGTAG, "Verify if selection is correct: "
        //      + MusicListAdapter.getItem(focusPosition));
    }

    private void upOneLevel() {
        File curPath = new File(MusicListAdapter.getCurDir());
        String upLevel = curPath.getParent();
        mStepsBack--;
        if (upLevel != null) {
            browseToDir(upLevel);
        } else {
            // Should never occur
            Log.e(LOGTAG, "upOneLevel, parent null");
        }
    }

    private final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1;

    private void checkStoragePermission() {
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.READ_EXTERNAL_STORAGE)) {
                showStoragePermissionReason();
            }

            // No explanation needed, we can request the permission.
            ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.READ_EXTERNAL_STORAGE },
                    MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Log.i(LOGTAG, "Granted storage permission");
                showFiles();
            } else {
                showStoragePermissionReason();
            }
            return;
        }
        }
    }

    private void showFiles() {
        String mediaPath = PsfDirectoryChoosePreference.getPsfRootDir(c);
        Log.d(LOGTAG, "Media Path is: " + mediaPath);
        browseToDir(mediaPath);
    }

    private void handleFirstTimeRun() {
        // Check if the psf root dir is set
        // If not, probably it's the first time run,
        // so ask user to set the psf root dir
        SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(c);
        if (!settings.contains(getString(R.string.key_psf_root_dir))) {
            Log.d(LOGTAG, "First time run");
            new AlertDialog.Builder(c).setMessage(R.string.first_time_run_dialog_msg)
                    .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            // Direct to the psf root dir setting
                            Intent intent = new Intent(c, PsfSettingsActivity.class);
                            intent.putExtra(getString(R.string.extra_direct_show_dir_dialog), true);
                            startActivity(intent);
                        }
                    }).create().show();
        }
    }
}