package com.lq.fragment;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import android.app.Activity;
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.res.Resources;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.provider.MediaStore.Audio.Media;
import android.provider.MediaStore.Audio.Playlists;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.PopupMenu;
import android.widget.TextView;
import android.widget.Toast;
import com.lq.activity.MainContentActivity;
import com.lq.xpressmusic.R;
import com.lq.adapter.PlaylistAdapter;
import com.lq.dao.PlaylistDAO;
import com.lq.entity.PlaylistInfo;
import com.lq.entity.TrackInfo;
import com.lq.fragment.EditTextDialogFragment.OnMyDialogInputListener;
import com.lq.loader.MusicRetrieveLoader;
import com.lq.loader.PlaylistInfoRetrieveLoader;
import com.lq.service.MusicService;
import com.lq.service.MusicService.MusicPlaybackLocalBinder;
import com.lq.util.Constant;
import com.lq.util.StringHelper;
/**
* @author lq 2013-6-1 lq2625304@gmail.com
* */
public class PlaylistBrowserFragment extends Fragment implements
LoaderCallbacks<List<PlaylistInfo>> {
private final String TAG = this.getClass().getSimpleName();
private final String SORT_ORDER = "sort_order";
private final int SORT_ORDER_CREATED_TIME = 1;
private final int SORT_ORDER_MODIFIED_TIME = 2;
private final int PLAYLIST_RETRIEVE_LOADER = 0;
private final int TRACK_RETRIEVE_LOADER = 1;
private final int CONTEXT_MENU_RENAME = 1;
private final int CONTEXT_MENU_DELETE = 2;
private final int CONTEXT_MENU_PLAYLATER = 3;
/** 手势检测 */
private GestureDetector mDetector = null;
private ImageView mView_MenuNavigation = null;
private ImageView mView_MoreFunctions = null;
private ImageView mView_GoToPlayer = null;
private TextView mView_Title = null;
private View mView_CreatePlaylist = null;
private ListView mView_ListView = null;
private PopupMenu mOverflowPopupMenu = null;
private PlaylistAdapter mAdapter = null;
private MainContentActivity mActivity = null;
private EditTextDialogFragment mEditTextDialogFragment = null;
private int mSelectedPlaylistId = -1;
private MusicPlaybackLocalBinder mMusicServiceBinder = null;
@Override
public void onAttach(Activity activity) {
Log.i(TAG, "onAttach");
super.onAttach(activity);
if (activity instanceof MainContentActivity) {
mActivity = (MainContentActivity) activity;
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate");
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.i(TAG, "onCreateView");
View rootView = inflater.inflate(R.layout.list_playlist, container,
false);
mView_ListView = (ListView) rootView
.findViewById(R.id.listview_playlist);
mView_MenuNavigation = (ImageView) rootView
.findViewById(R.id.menu_navigation);
mView_Title = (TextView) rootView.findViewById(R.id.title_of_top);
mView_GoToPlayer = (ImageView) rootView
.findViewById(R.id.switch_to_player);
mView_CreatePlaylist = (View) rootView.findViewById(R.id.add_playlist);
mView_MoreFunctions = (ImageView) rootView
.findViewById(R.id.more_functions);
mOverflowPopupMenu = new PopupMenu(getActivity(), mView_MoreFunctions);
mOverflowPopupMenu.getMenuInflater().inflate(
R.menu.popup_playlist_list, mOverflowPopupMenu.getMenu());
return rootView;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
Log.i(TAG, "onActivityCreated");
super.onActivityCreated(savedInstanceState);
initViewsSetting();
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
// sd card 可用
// 加载数据
getLoaderManager().initLoader(PLAYLIST_RETRIEVE_LOADER, null, this);
} else {
// 当前不可用
Toast.makeText(getActivity(),
getResources().getString(R.string.sdcard_cannot_use),
Toast.LENGTH_SHORT).show();
}
}
@Override
public void onStart() {
Log.i(TAG, "onStart");
super.onStart();
// 本Activity界面显示时绑定服务,服务发送消息给本Activity以更新UI
getActivity().bindService(
new Intent(getActivity(), MusicService.class),
mServiceConnection, Context.BIND_AUTO_CREATE);
}
@Override
public void onResume() {
Log.i(TAG, "onResume");
super.onResume();
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
// sd card 可用
// 显示操作栏
mView_MoreFunctions.setClickable(true);
mView_CreatePlaylist.setVisibility(View.VISIBLE);
mView_Title.setText("");
// 初始化一个装载器,根据第一个参数,要么连接一个已存在的装载器,要么以此ID创建一个新的装载器
getLoaderManager().initLoader(PLAYLIST_RETRIEVE_LOADER, null, this);
} else {
// 当前不可用
// 隐藏操作栏
mView_MoreFunctions.setClickable(false);
mView_CreatePlaylist.setVisibility(View.GONE);
// 提示SD卡不可用
Toast.makeText(getActivity(), R.string.sdcard_cannot_use,
Toast.LENGTH_SHORT).show();
}
startWatchingExternalStorage();
}
@Override
public void onStop() {
Log.i(TAG, "onStop");
super.onStop();
// 本界面不可见时取消绑定服务
getActivity().unbindService(mServiceConnection);
getActivity().unregisterReceiver(mExternalStorageReceiver);
}
@Override
public void onDetach() {
super.onDetach();
mActivity = null;
}
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy");
super.onDestroy();
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
final AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
menu.setHeaderTitle(mAdapter.getItem(info.position).getPlaylistName());
menu.add(0, CONTEXT_MENU_PLAYLATER, Menu.NONE, R.string.play_later);
menu.add(0, CONTEXT_MENU_RENAME, Menu.NONE, R.string.rename);
menu.add(0, CONTEXT_MENU_DELETE, Menu.NONE, R.string.delete);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
final AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) item
.getMenuInfo();
mSelectedPlaylistId = mAdapter.getItem(menuInfo.position).getId();
DialogFragment dialogF;
switch (item.getItemId()) {
case CONTEXT_MENU_PLAYLATER:
// 追加选择的歌曲条目到后台的正在播放的列表中
getLoaderManager().restartLoader(TRACK_RETRIEVE_LOADER, null,
mTracksLoaderCallbacks);
break;
case CONTEXT_MENU_RENAME:
// 弹出重命名的对话框
mEditTextDialogFragment = EditTextDialogFragment.newInstance(
getResources().getString(R.string.rename), mAdapter
.getItem(menuInfo.position).getPlaylistName(),
null, mUpdatePlaylistListener);
mEditTextDialogFragment.show(getFragmentManager(), null);
break;
case CONTEXT_MENU_DELETE:
// 弹出确认删除的提醒对话框
String title = getResources().getString(
R.string.are_you_sure_to_delete)
+ "\""
+ mAdapter.getItem(menuInfo.position).getPlaylistName()
+ "\"" + getResources().getString(R.string.question_mark);
dialogF = PromptDialogFragment.newInstance(title,
mDeletePromptListener);
dialogF.show(getFragmentManager(), null);
break;
default:
return false;
}
return false;
}
private void initViewsSetting() {
// 设置滑动手势
mDetector = new GestureDetector(new SimpleOnGestureListener() {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
// 从右向左滑动
if (e1 != null && e2 != null) {
if (e1.getX() - e2.getX() > 120) {
mActivity.switchToPlayer();
return true;
}
}
return false;
}
});
View.OnTouchListener gestureListener = new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (mDetector.onTouchEvent(event)) {
return true;
}
return false;
}
};
mView_ListView.setOnTouchListener(gestureListener);
mAdapter = new PlaylistAdapter(getActivity());
mView_ListView.setAdapter(mAdapter);
registerForContextMenu(mView_ListView);
mView_ListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// TODO列表点击,进入音乐列表
if (getParentFragment() instanceof FramePlaylistFragment) {
Bundle args = new Bundle();
args.putInt(Constant.PARENT, Constant.START_FROM_PLAYLIST);
args.putParcelable(PlaylistInfo.class.getSimpleName(),
mAdapter.getItem(position));
getFragmentManager()
.beginTransaction()
.replace(
R.id.frame_for_nested_fragment,
Fragment.instantiate(getActivity(),
TrackBrowserFragment.class
.getName(), args))
.addToBackStack(null).commit();
}
}
});
mView_Title.setText(R.string.local_playlist);
mView_GoToPlayer.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mActivity.switchToPlayer();
}
});
mView_MenuNavigation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mActivity.getSlidingMenu().showMenu();
}
});
mView_CreatePlaylist.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Resources r = getResources();
mEditTextDialogFragment = EditTextDialogFragment.newInstance(
r.getString(R.string.create_playlist), null,
r.getString(R.string.input_playlist_name),
mCreateNewPlaylistListener);
mEditTextDialogFragment.show(getFragmentManager(),
"createNewPlaylist");
}
});
mView_MoreFunctions.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mOverflowPopupMenu.show();
}
});
mOverflowPopupMenu
.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
Bundle args;
switch (item.getItemId()) {
case R.id.sort_by_playlist_name:
Collections.sort(mAdapter.getData(),
mPlaylistNameComparator);
mAdapter.notifyDataSetChanged();
break;
case R.id.sort_by_playlist_music_count:
Collections.sort(mAdapter.getData(),
mPlaylistSongCountComparator);
mAdapter.notifyDataSetChanged();
break;
case R.id.sort_by_playlist_created_time:
args = new Bundle();
args.putInt(SORT_ORDER, SORT_ORDER_CREATED_TIME);
getLoaderManager().restartLoader(
PLAYLIST_RETRIEVE_LOADER, args,
PlaylistBrowserFragment.this);
break;
case R.id.sort_by_playlist_modified_time:
args = new Bundle();
args.putInt(SORT_ORDER, SORT_ORDER_MODIFIED_TIME);
getLoaderManager().restartLoader(
PLAYLIST_RETRIEVE_LOADER, args,
PlaylistBrowserFragment.this);
break;
default:
break;
}
return true;
}
});
}
@Override
public Loader<List<PlaylistInfo>> onCreateLoader(int id, Bundle args) {
Log.i(TAG, "onCreateLoader");
String sortOrder = null;
if (args != null) {
switch (args.getInt(SORT_ORDER, -1)) {
case SORT_ORDER_CREATED_TIME:
sortOrder = Playlists.DATE_ADDED;
break;
case SORT_ORDER_MODIFIED_TIME:
sortOrder = Playlists.DATE_MODIFIED;
break;
default:
break;
}
}
return new PlaylistInfoRetrieveLoader(getActivity(), null, null,
sortOrder);
}
@Override
public void onLoadFinished(Loader<List<PlaylistInfo>> loader,
List<PlaylistInfo> data) {
Log.i(TAG, "onLoadFinished");
// 载入完成,更新列表数据
mAdapter.setData(data);
// 在标题栏上显示艺术家数目
if (data != null && data.size() != 0) {
mView_Title.setText(getResources().getString(
R.string.local_playlist)
+ "(" + data.size() + ")");
}
}
@Override
public void onLoaderReset(Loader<List<PlaylistInfo>> loader) {
Log.i(TAG, "onLoaderReset");
mAdapter.setData(null);
}
private void startWatchingExternalStorage() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
intentFilter.addAction(Intent.ACTION_MEDIA_REMOVED);
intentFilter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);
intentFilter.addAction(Intent.ACTION_MEDIA_EJECT);
intentFilter.setPriority(1000);
intentFilter.addDataScheme("file");
getActivity().registerReceiver(mExternalStorageReceiver, intentFilter);
}
private BroadcastReceiver mExternalStorageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_MEDIA_EJECT)
|| intent.getAction().equals(Intent.ACTION_MEDIA_REMOVED)
|| intent.getAction().equals(
Intent.ACTION_MEDIA_BAD_REMOVAL)) {
// SD卡移除,设置列表为空
mView_MoreFunctions.setClickable(false);
mView_CreatePlaylist.setVisibility(View.GONE);
mView_Title.setText("");
mAdapter.setData(null);
// 提示SD卡不可用
Toast.makeText(getActivity(), R.string.sdcard_cannot_use,
Toast.LENGTH_SHORT).show();
} else if (intent.getAction().equals(Intent.ACTION_MEDIA_MOUNTED)) {
// SD卡正常挂载,重新加载数据
mView_MoreFunctions.setClickable(true);
mView_CreatePlaylist.setVisibility(View.VISIBLE);
getLoaderManager().restartLoader(PLAYLIST_RETRIEVE_LOADER,
null, PlaylistBrowserFragment.this);
}
}
};
private OnMyDialogInputListener mCreateNewPlaylistListener = new OnMyDialogInputListener() {
@Override
public void onEditTextInputCompleted(String newListName) {
int newListId = PlaylistDAO.createPlaylist(getActivity()
.getContentResolver(), newListName);
if (newListId == -1) {
// 有重名播放列表,提示列表名已经存在
Toast.makeText(
getActivity(),
getActivity().getString(
R.string.playlist_has_already_existed),
Toast.LENGTH_SHORT).show();
mEditTextDialogFragment.setDialogStayShown();
} else {
// 新建后重新读取播放列表数据库
getLoaderManager().restartLoader(PLAYLIST_RETRIEVE_LOADER,
null, PlaylistBrowserFragment.this);
mEditTextDialogFragment.setDialogDismiss();
}
}
};
private OnMyDialogInputListener mUpdatePlaylistListener = new OnMyDialogInputListener() {
@Override
public void onEditTextInputCompleted(String newListName) {
// 尝试更新播放列表名称
boolean isRename = PlaylistDAO.updatePlaylistName(getActivity()
.getContentResolver(), newListName, mSelectedPlaylistId);
if (isRename) {
// 有重名播放列表,提示列表名已经存在
Toast.makeText(
getActivity(),
getActivity().getString(
R.string.playlist_has_already_existed),
Toast.LENGTH_SHORT).show();
mEditTextDialogFragment.setDialogStayShown();
} else {
// 新建后重新读取播放列表数据库
getLoaderManager().restartLoader(PLAYLIST_RETRIEVE_LOADER,
null, PlaylistBrowserFragment.this);
mEditTextDialogFragment.setDialogDismiss();
}
}
};
private DialogInterface.OnClickListener mDeletePromptListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 删除指定的播放列表
PlaylistDAO.deletePlaylist(getActivity().getContentResolver(),
mSelectedPlaylistId);
// 重新读取数据库,更新列表显示
getLoaderManager().restartLoader(PLAYLIST_RETRIEVE_LOADER, null,
PlaylistBrowserFragment.this);
}
};
/** 与Service连接时交互的类 */
private ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
Log.i(TAG, "onServiceConnected");
// 保持对Service的Binder引用,以便调用Service提供给客户端的方法
mMusicServiceBinder = (MusicPlaybackLocalBinder) service;
}
// 与服务端连接异常丢失时才调用,调用unBindService不调用此方法哎
public void onServiceDisconnected(ComponentName className) {
Log.i(TAG, "onServiceDisconnected");
}
};
private LoaderManager.LoaderCallbacks<List<TrackInfo>> mTracksLoaderCallbacks = new LoaderCallbacks<List<TrackInfo>>() {
@Override
public Loader<List<TrackInfo>> onCreateLoader(int id, Bundle args) {
Log.i(TAG, "onCreateLoader");
String sortOrder = Media.TITLE_KEY;
// 查询语句:检索出.mp3为后缀名,时长大于1分钟,文件大小大于1MB的媒体文件
StringBuffer where = new StringBuffer("(" + Media.DATA
+ " like'%.mp3' or " + Media.DATA + " like'%.wma') and "
+ Media.DURATION + " > " + 1000 * 60 * 1 + " and "
+ Media.SIZE + " > " + 1024);
where.append(" and " + Media._ID + " in (select "
+ Playlists.Members.AUDIO_ID
+ " from audio_playlists_map where "
+ Playlists.Members.PLAYLIST_ID + "=" + mSelectedPlaylistId
+ ")");
return new MusicRetrieveLoader(getActivity(), where.toString(),
null, sortOrder);
}
@Override
public void onLoaderReset(Loader<List<TrackInfo>> loader) {
Log.i(TAG, "onLoaderReset");
}
@Override
public void onLoadFinished(Loader<List<TrackInfo>> loader,
List<TrackInfo> data) {
Log.i(TAG, "onLoadFinished");
if (mMusicServiceBinder != null) {
// 数据载入完毕,追加到当前播放列表后
mMusicServiceBinder.appendToCurrentPlayList(data);
}
}
};
// 按歌曲数量倒序排序
private Comparator<PlaylistInfo> mPlaylistSongCountComparator = new Comparator<PlaylistInfo>() {
@Override
public int compare(PlaylistInfo lhs, PlaylistInfo rhs) {
if (lhs.getNumOfMembers() > rhs.getNumOfMembers()) {
return -1;
} else if (lhs.getNumOfMembers() < rhs.getNumOfMembers()) {
return 1;
} else {
return 0;
}
}
};
// 按播放列表名称顺序排序
private Comparator<PlaylistInfo> mPlaylistNameComparator = new Comparator<PlaylistInfo>() {
char first_l, first_r;
@Override
public int compare(PlaylistInfo lhs, PlaylistInfo rhs) {
first_l = lhs.getPlaylistName().charAt(0);
first_r = rhs.getPlaylistName().charAt(0);
if (StringHelper.checkType(first_l) == StringHelper.CharType.CHINESE) {
first_l = StringHelper.getPinyinFirstLetter(first_l);
}
if (StringHelper.checkType(first_r) == StringHelper.CharType.CHINESE) {
first_r = StringHelper.getPinyinFirstLetter(first_r);
}
if (first_l > first_r) {
return 1;
} else if (first_l < first_r) {
return -1;
} else {
return 0;
}
}
};
}