package com.lq.fragment; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; 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.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Environment; import android.os.IBinder; import android.preference.PreferenceManager; 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.content.Loader; import android.text.Editable; import android.text.InputType; import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; import android.text.TextWatcher; import android.text.style.ImageSpan; 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.Gravity; 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.View.OnLongClickListener; import android.view.ViewGroup; import android.view.WindowManager.LayoutParams; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.AdapterView.OnItemClickListener; import android.widget.EditText; import android.widget.ImageView; import android.widget.ListView; import android.widget.PopupMenu; import android.widget.PopupWindow; import android.widget.TextView; import android.widget.Toast; import com.lq.activity.MainContentActivity; import com.lq.activity.MainContentActivity.OnBackKeyPressedListener; import com.lq.activity.MutipleEditActivity; import com.lq.xpressmusic.R; import com.lq.adapter.TrackAdapter; import com.lq.dao.PlaylistDAO; import com.lq.entity.AlbumInfo; import com.lq.entity.ArtistInfo; import com.lq.entity.FolderInfo; import com.lq.entity.PlaylistInfo; import com.lq.entity.TrackInfo; import com.lq.listener.OnPlaybackStateChangeListener; import com.lq.loader.MusicRetrieveLoader; 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 TrackBrowserFragment extends Fragment implements LoaderManager.LoaderCallbacks<List<TrackInfo>>, OnItemClickListener, OnBackKeyPressedListener { // 调试用的标记 private final String TAG = this.getClass().getSimpleName(); private static final int MUSIC_RETRIEVE_LOADER = 0; private final int CONTEXT_MENU_ADD_TO_PLAYLIST = 1; private final int CONTEXT_MENU_CHECK_DETAIL = 2; private final int CONTEXT_MENU_DELETE = 3; /** 手势检测 */ private GestureDetector mDetector = null; private String mSortOrder = Media.TITLE_KEY; private Bundle mCurrentPlayInfo = null; private boolean mHasNewData = false; private MainContentActivity mActivity = null; /** 显示本地音乐的列表 */ private ListView mView_ListView = null; private View mView_EmptyNoStorage = null; private View mView_EmptyNoSong = null; private View mView_EmptyLoading = null; private ImageView mView_MenuNavigation = null; private ImageView mView_GoToPlayer = null; private ImageView mView_MoreFunctions = null; private TextView mView_Title = null; private View mView_PlayAll = null; private View mView_Search = null; private View mView_MutipleChoose = null; private View mView_SearchBar = null; private EditText mView_SearchInput = null; private View mView_SearchCancel = null; private View mView_TrackOperations = null; private ImageView mView_KeyboardSwitcher = null; /** 弹出的搜索软键盘是否是自定义的T9键盘 */ private boolean mIsT9Keyboard = true; private PopupMenu mOverflowPopupMenu = null; private PopupWindow mT9KeyBoardWindow = null; /** 用来绑定数据至ListView的适配器 */ private TrackAdapter mAdapter = null; private List<TrackInfo> mOriginalData = new ArrayList<TrackInfo>(); private List<TrackInfo> mShowData = new ArrayList<TrackInfo>(); private ArtistInfo mArtistInfo = null; private FolderInfo mFolderInfo = null; private PlaylistInfo mPlaylistInfo = null; private AlbumInfo mAlbumInfo = null; private TrackInfo mToDeleteTrack = null; private TrackInfo mPlayingTrack = null; private SharedPreferences mSystemPreferences = null; private InputMethodManager mInputMethodManager = null; private MusicPlaybackLocalBinder mMusicServiceBinder = null; /** 与Service连接时交互的类 */ private ServiceConnection mServiceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { Log.i(TAG, "onServiceConnected"); mMusicServiceBinder = (MusicPlaybackLocalBinder) service; mMusicServiceBinder .registerOnPlaybackStateChangeListener(mOnPlaybackStateChangeListener); mCurrentPlayInfo = mMusicServiceBinder.getCurrentPlayInfo(); } // 与服务端连接异常丢失时才调用,调用unBindService不调用此方法哎 public void onServiceDisconnected(ComponentName className) { } }; /** 文件过滤设置改变的话重新加载显示数据 */ private OnSharedPreferenceChangeListener mFilterPreferenceChangedListener = new OnSharedPreferenceChangeListener() { @Override public void onSharedPreferenceChanged( SharedPreferences sharedPreferences, String key) { if (key.equals(SettingFragment.KEY_FILTER_BY_SIZE) || key.equals(SettingFragment.KEY_FILTER_BY_DURATION)) { // 歌曲过滤设置改变了 if (!isDetached() && Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { // 并且本页面处于可见状态,重新更新数据显示 mView_Title.setText(""); mView_ListView.setEmptyView(mView_EmptyLoading); mAdapter.setData(null); mView_TrackOperations.setVisibility(View.GONE); mView_MoreFunctions.setClickable(false); getLoaderManager().restartLoader(MUSIC_RETRIEVE_LOADER, null, TrackBrowserFragment.this); } } } }; @Override public void onAttach(Activity activity) { Log.i(TAG, "onAttach"); super.onAttach(activity); if (activity instanceof MainContentActivity) { mActivity = (MainContentActivity) activity; } mSystemPreferences = PreferenceManager .getDefaultSharedPreferences(getActivity()); mSystemPreferences .registerOnSharedPreferenceChangeListener(mFilterPreferenceChangedListener); } @Override public void onCreate(Bundle savedInstanceState) { Log.i(TAG, "onCreate"); super.onCreate(savedInstanceState); mInputMethodManager = (InputMethodManager) getActivity() .getSystemService(Context.INPUT_METHOD_SERVICE); } /** 在此加载一个ListView,可以使用自定义的ListView */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.i(TAG, "onCreateView"); ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.list_track, container, false); mView_ListView = (ListView) rootView .findViewById(R.id.listview_local_music); mView_EmptyNoStorage = rootView.findViewById(R.id.empty_no_sdcard); mView_EmptyNoSong = rootView.findViewById(R.id.empty_no_song); mView_EmptyLoading = rootView.findViewById(R.id.empty_loading); mView_MenuNavigation = (ImageView) rootView .findViewById(R.id.menu_navigation); mView_Title = (TextView) rootView.findViewById(R.id.title_of_top); mView_PlayAll = (View) rootView.findViewById(R.id.btn_play_all); mView_Search = (View) rootView.findViewById(R.id.btn_search); mView_MutipleChoose = (View) rootView .findViewById(R.id.btn_mutiple_choose); mView_MoreFunctions = (ImageView) rootView .findViewById(R.id.more_functions); mView_GoToPlayer = (ImageView) rootView .findViewById(R.id.switch_to_player); mView_SearchBar = (View) rootView.findViewById(R.id.search_bar); mView_KeyboardSwitcher = (ImageView) rootView .findViewById(R.id.keyboard_switcher); mView_SearchInput = (EditText) rootView.findViewById(R.id.search_input); mView_SearchCancel = (View) rootView.findViewById(R.id.cancel_search); mView_TrackOperations = (View) rootView .findViewById(R.id.track_operations); mOverflowPopupMenu = new PopupMenu(getActivity(), mView_MoreFunctions); Bundle args = getArguments(); if (args != null) { switch (args.getInt(Constant.PARENT)) { case Constant.START_FROM_LOCAL_MUSIC: mOverflowPopupMenu.getMenuInflater().inflate( R.menu.popup_local_music_list, mOverflowPopupMenu.getMenu()); break; default: mOverflowPopupMenu.getMenuInflater().inflate( R.menu.popup_track_list, mOverflowPopupMenu.getMenu()); break; } } return rootView; } /** 延迟ListView的设置到Activity创建时,为ListView绑定数据适配器 */ @Override public void onActivityCreated(Bundle savedInstanceState) { Log.i(TAG, "onActivityCreated"); super.onActivityCreated(savedInstanceState); initViewsSetting(); handleArguments(); // 初始化一个装载器,根据第一个参数,要么连接一个已存在的装载器,要么以此ID创建一个新的装载器 getLoaderManager().initLoader(MUSIC_RETRIEVE_LOADER, null, this); } @Override public void onStart() { Log.i(TAG, "onStart"); super.onStart(); // 在Fragment可见时绑定服务 ,以使服务可以发送消息过来 getActivity().bindService( new Intent(getActivity(), MusicService.class), mServiceConnection, Context.BIND_AUTO_CREATE); if (mActivity instanceof MainContentActivity) { mActivity.registerBackKeyPressedListener(this); } } @Override public void onResume() { Log.i(TAG, "onResume"); super.onResume(); startWatchingExternalStorage(); } @Override public void onSaveInstanceState(Bundle outState) { Log.i(TAG, "onSaveInstanceState"); super.onSaveInstanceState(outState); } @Override public void onStop() { Log.i(TAG, "onStop"); super.onStop(); mActivity.unregisterBackKeyPressedListener(this); // Fragment不可见时,无需更新UI,取消服务绑定 mActivity.unbindService(mServiceConnection); mMusicServiceBinder .unregisterOnPlaybackStateChangeListener(mOnPlaybackStateChangeListener); mMusicServiceBinder = null; getActivity().unregisterReceiver(mExternalStorageReceiver); } @Override public void onDetach() { Log.i(TAG, "onDetach"); super.onDetach(); mSystemPreferences .unregisterOnSharedPreferenceChangeListener(mFilterPreferenceChangedListener); } @Override public void onDestroy() { Log.i(TAG, "onDestroy"); super.onDestroy(); mPlayingTrack = null; mAdapter = null; mActivity = null; mArtistInfo = null; mPlaylistInfo = null; mFolderInfo = null; mAlbumInfo = null; mCurrentPlayInfo = null; mShowData.clear(); mShowData = null; mOriginalData.clear(); mOriginalData = null; } @Override public void onBackKeyPressed() { // 按下返回键时关闭T9键盘 if (mT9KeyBoardWindow != null) { if (mT9KeyBoardWindow.isShowing()) { mT9KeyBoardWindow.dismiss(); } } } /** 初始化各个视图组件的设置 */ 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); // ListView的设置------------------------------------------------------------- // 创建一个空的适配器,用来显示加载的数据,适配器内容稍后由Loader填充 mAdapter = new TrackAdapter(getActivity()); // 为ListView绑定数据适配器 mView_ListView.setAdapter(mAdapter); registerForContextMenu(mView_ListView); // 为ListView的条目绑定一个点击事件监听 mView_ListView.setOnItemClickListener(this); mView_ListView.setEmptyView(mView_EmptyLoading); // 标题的设置------------------------------------------------------------- mView_Title.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // 标题作为回退导航 getFragmentManager().popBackStackImmediate(); } }); // 默认不可点击 mView_Title.setClickable(false); // 跳转至播放界面----------------------------------------------- mView_GoToPlayer.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mActivity.switchToPlayer(); } }); // 顶部弹出菜单---------------------------------------------------- mOverflowPopupMenu .setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case R.id.sort_by_music_name: mSortOrder = Media.TITLE_KEY; getLoaderManager().restartLoader( MUSIC_RETRIEVE_LOADER, null, TrackBrowserFragment.this); break; case R.id.sort_by_artist_name: mSortOrder = Media.ARTIST_KEY; getLoaderManager().restartLoader( MUSIC_RETRIEVE_LOADER, null, TrackBrowserFragment.this); break; case R.id.classify_by_artist: if (null != getParentFragment() && getParentFragment() instanceof FrameLocalMusicFragment) { getFragmentManager() .beginTransaction() .replace( R.id.frame_for_nested_fragment, Fragment.instantiate( getActivity(), ArtistBrowserFragment.class .getName(), null)) .addToBackStack(null).commit(); } break; case R.id.classify_by_album: if (null != getParentFragment() && getParentFragment() instanceof FrameLocalMusicFragment) { getFragmentManager() .beginTransaction() .replace( R.id.frame_for_nested_fragment, Fragment.instantiate( getActivity(), AlbumBrowserFragment.class .getName(), null)) .addToBackStack(null).commit(); } break; case R.id.classify_by_folder: if (null != getParentFragment() && getParentFragment() instanceof FrameLocalMusicFragment) { getFragmentManager() .beginTransaction() .replace( R.id.frame_for_nested_fragment, Fragment.instantiate( getActivity(), FolderBrowserFragment.class .getName(), null)) .addToBackStack(null).commit(); } break; default: break; } return true; } }); mView_MoreFunctions.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mOverflowPopupMenu.show(); } }); // 侧滑菜单弹出按钮------------------------------------------------ mView_MenuNavigation.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mIsT9Keyboard) { mT9KeyBoardWindow.dismiss(); } mActivity.getSlidingMenu().showMenu(); } }); // 多选按钮----------------------------------------------------------- mView_MutipleChoose.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(getActivity(), MutipleEditActivity.class); Bundle data = new Bundle(); // 传递参数给多选界面 switch (getArguments().getInt(Constant.PARENT)) { case Constant.START_FROM_LOCAL_MUSIC: data.putString(Constant.TITLE, getResources().getString(R.string.local_music)); data.putInt(Constant.PARENT, Constant.START_FROM_LOCAL_MUSIC); break; case Constant.START_FROM_ARTIST: data.putString(Constant.TITLE, mArtistInfo.getArtistName()); data.putInt(Constant.PARENT, Constant.START_FROM_ARTIST); break; case Constant.START_FROM_FOLER: data.putString(Constant.TITLE, mFolderInfo.getFolderName()); data.putInt(Constant.PARENT, Constant.START_FROM_FOLER); break; case Constant.START_FROM_PLAYLIST: data.putString(Constant.TITLE, mPlaylistInfo.getPlaylistName()); data.putInt(Constant.PARENT, Constant.START_FROM_PLAYLIST); data.putInt(Constant.PLAYLIST_ID, mPlaylistInfo.getId()); break; case Constant.START_FROM_ALBUM: data.putString(Constant.TITLE, mAlbumInfo.getAlbumName()); data.putInt(Constant.PARENT, Constant.START_FROM_ALBUM); break; default: break; } data.putInt(Constant.FIRST_VISIBLE_POSITION, mView_ListView.getFirstVisiblePosition()); data.putParcelableArrayList(Constant.DATA_LIST, mAdapter.getData()); intent.putExtras(data); startActivity(intent); } }); // 全部播放按钮---------------------------------------------------------- mView_PlayAll.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mHasNewData && mMusicServiceBinder != null) { mMusicServiceBinder.setCurrentPlayList(mAdapter.getData()); } mHasNewData = false; Intent intent = new Intent(MusicService.ACTION_PLAY); mActivity.startService(intent); mActivity.switchToPlayer(); } }); // 搜索相关------------------------------------------------------------- OnClickListener searchbarClickListner = new OnClickListener() { @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_search: // 显示搜索条,隐藏歌曲操作条 mView_TrackOperations.setVisibility(View.GONE); mView_SearchBar.setVisibility(View.VISIBLE); mView_KeyboardSwitcher .setImageResource(R.drawable.keyboard_switch); mIsT9Keyboard = true; // 弹出T9键盘 mT9KeyBoardWindow.showAtLocation(getView(), Gravity.BOTTOM, 0, 0); // 搜索输入框禁止输入法输入 mView_SearchInput.setInputType(InputType.TYPE_NULL); mView_SearchInput.requestFocus(); break; case R.id.cancel_search: mView_SearchBar.setVisibility(View.GONE); mView_TrackOperations.setVisibility(View.VISIBLE); mView_SearchInput.setText(""); mView_SearchInput .setHint(R.string.please_input_jianpin_or_quanpin); if (mIsT9Keyboard) {// 如果T9键盘开启,则隐藏 mT9KeyBoardWindow.dismiss(); } else {// 如果T9键盘未开启 // 隐藏输入法 mInputMethodManager.hideSoftInputFromWindow( mView_SearchInput.getWindowToken(), 0); } break; case R.id.keyboard_switcher: mIsT9Keyboard = !mIsT9Keyboard;// 置反一下 if (mIsT9Keyboard) {// 如果T9键盘开启了 mView_KeyboardSwitcher .setImageResource(R.drawable.keyboard_switch); mView_SearchInput .setHint(R.string.please_input_jianpin_or_quanpin); // 搜索输入框禁止输入法输入 mView_SearchInput.setInputType(InputType.TYPE_NULL); // 隐藏输入法 mInputMethodManager.hideSoftInputFromWindow( mView_SearchInput.getWindowToken(), 0); // 弹出T9键盘 mT9KeyBoardWindow.showAtLocation(getView(), Gravity.BOTTOM, 0, 0); } else {// 如果T9键盘关闭了 mT9KeyBoardWindow.dismiss(); mView_KeyboardSwitcher .setImageResource(R.drawable.keyboard_switch_9); mView_SearchInput .setHint(R.string.please_input_song_or_artist_name); // 显示输入法 mInputMethodManager.showSoftInput(mView_SearchInput, 0); // 搜索输入框允许输入法输入 mView_SearchInput .setInputType(InputType.TYPE_CLASS_TEXT); } break; case R.id.search_input: if (mIsT9Keyboard) { if (!mT9KeyBoardWindow.isShowing()) { mT9KeyBoardWindow.showAtLocation(getView(), Gravity.BOTTOM, 0, 0); } } break; default: break; } } }; mView_Search.setOnClickListener(searchbarClickListner); mView_SearchCancel.setOnClickListener(searchbarClickListner); mView_KeyboardSwitcher.setOnClickListener(searchbarClickListner); mView_SearchInput.setOnClickListener(searchbarClickListner); // T9键盘的设置--------------------------------------------------------------- // 加载布局 ViewGroup t9Layout = (ViewGroup) LayoutInflater.from(getActivity()) .inflate(R.layout.t9_keyboard, null, false); t9Layout.findViewById(R.id.t9_key_2).setOnClickListener( mT9KeyClickedListener); t9Layout.findViewById(R.id.t9_key_3).setOnClickListener( mT9KeyClickedListener); t9Layout.findViewById(R.id.t9_key_4).setOnClickListener( mT9KeyClickedListener); t9Layout.findViewById(R.id.t9_key_5).setOnClickListener( mT9KeyClickedListener); t9Layout.findViewById(R.id.t9_key_6).setOnClickListener( mT9KeyClickedListener); t9Layout.findViewById(R.id.t9_key_7).setOnClickListener( mT9KeyClickedListener); t9Layout.findViewById(R.id.t9_key_8).setOnClickListener( mT9KeyClickedListener); t9Layout.findViewById(R.id.t9_key_9).setOnClickListener( mT9KeyClickedListener); t9Layout.findViewById(R.id.t9_exit).setOnClickListener( mT9KeyClickedListener); View deleteKey = t9Layout.findViewById(R.id.t9_delete); deleteKey.setOnClickListener(mT9KeyClickedListener); deleteKey.setOnLongClickListener(new OnLongClickListener() { @Override public boolean onLongClick(View v) { // 长按删除,删除所有输入内容 Editable et = mView_SearchInput.getText(); if (!et.toString().equals("")) { et.clear(); mView_SearchInput.setText(et); mView_SearchInput.setSelection(0); return true; } return false; } }); // 设置T9键盘弹出窗口属性 mT9KeyBoardWindow = new PopupWindow(getActivity()); mT9KeyBoardWindow.setOutsideTouchable(false); mT9KeyBoardWindow.setWidth(LayoutParams.MATCH_PARENT); mT9KeyBoardWindow.setHeight(LayoutParams.WRAP_CONTENT); mT9KeyBoardWindow.setFocusable(true); mT9KeyBoardWindow.setContentView(t9Layout); mT9KeyBoardWindow.setAnimationStyle(R.style.t9_window_anim); // 搜索输入框文本变化监听 mView_SearchInput.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // 输入框文字改变时过滤歌曲列表 if (TextUtils.isEmpty(s)) { mAdapter.setData(mOriginalData); } else if (mIsT9Keyboard) { // T9键盘开启,进行简拼全拼搜索 pinyinSearch(s.toString()); } else { // 普通的模糊搜索 pinyinSearch(StringHelper.getPingYin(s.toString())); } } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { if (mPlayingTrack != null) { mAdapter.setSpecifiedIndicator(MusicService .seekPosInListById(mAdapter.getData(), mPlayingTrack.getId())); } else { mAdapter.setSpecifiedIndicator(-1); } } }); // 初始时不显示操作条,数据加载完再显示 mView_TrackOperations.setVisibility(View.GONE); mView_MoreFunctions.setClickable(false); } /** T9键盘按键处理 */ private OnClickListener mT9KeyClickedListener = new OnClickListener() { @Override public void onClick(View v) { switch (v.getId()) { case R.id.t9_key_2: appendImageSpan(R.drawable.keyboard_edit_2, 2); break; case R.id.t9_key_3: appendImageSpan(R.drawable.keyboard_edit_3, 3); break; case R.id.t9_key_4: appendImageSpan(R.drawable.keyboard_edit_4, 4); break; case R.id.t9_key_5: appendImageSpan(R.drawable.keyboard_edit_5, 5); break; case R.id.t9_key_6: appendImageSpan(R.drawable.keyboard_edit_6, 6); break; case R.id.t9_key_7: appendImageSpan(R.drawable.keyboard_edit_7, 7); break; case R.id.t9_key_8: appendImageSpan(R.drawable.keyboard_edit_8, 8); break; case R.id.t9_key_9: appendImageSpan(R.drawable.keyboard_edit_9, 9); break; case R.id.t9_exit: mT9KeyBoardWindow.dismiss(); break; case R.id.t9_delete: backDeleteImageSpan(); break; default: break; } } }; @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (mHasNewData && mMusicServiceBinder != null) { mMusicServiceBinder.setCurrentPlayList(mAdapter.getData()); } mHasNewData = false; Intent intent = new Intent(MusicService.ACTION_PLAY); intent.putExtra(Constant.REQUEST_PLAY_ID, mAdapter.getItem(position) .getId()); intent.putExtra(Constant.CLICK_ITEM_IN_LIST, true); mActivity.startService(intent); mActivity.switchToPlayer(); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); final AdapterContextMenuInfo mInfo = (AdapterContextMenuInfo) menuInfo; menu.setHeaderTitle(mAdapter.getItem(mInfo.position).getTitle()); menu.add(0, CONTEXT_MENU_ADD_TO_PLAYLIST, Menu.NONE, R.string.add_to_playlist); menu.add(0, CONTEXT_MENU_CHECK_DETAIL, Menu.NONE, R.string.check_detail); switch (getArguments().getInt(Constant.PARENT)) { case Constant.START_FROM_PLAYLIST: menu.add(0, CONTEXT_MENU_DELETE, Menu.NONE, R.string.remove); break; default: menu.add(0, CONTEXT_MENU_DELETE, Menu.NONE, R.string.delete); break; } } @Override public boolean onContextItemSelected(MenuItem item) { DialogFragment df = null; final AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) item .getMenuInfo(); Log.i(TAG, "menuInfo:" + menuInfo); switch (item.getItemId()) { case CONTEXT_MENU_ADD_TO_PLAYLIST: // 弹出选择播放列表的窗口 df = SelectPlaylistDialogFragment.newInstance(new long[] { mAdapter .getItem(menuInfo.position).getId() }); df.show(getFragmentManager(), null); break; case CONTEXT_MENU_CHECK_DETAIL: // 弹出歌曲详细信息的窗口 df = TrackDetailDialogFragment.newInstance(mAdapter .getItem(menuInfo.position)); df.show(getFragmentManager(), null); break; case CONTEXT_MENU_DELETE: // 弹出确认删除的提示窗口 mToDeleteTrack = mAdapter.getItem(menuInfo.position); switch (getArguments().getInt(Constant.PARENT)) { case Constant.START_FROM_PLAYLIST: df = PromptDialogFragment.newInstance( getResources().getString( R.string.confirm_remove_song_from_playlist), mDeletePromptListener); df.show(getFragmentManager(), null); break; default: df = PromptDialogFragment.newInstance( getResources().getString( R.string.confirm_delete_song_file), mDeletePromptListener); df.show(getFragmentManager(), null); break; } break; default: return false; } return true; } /** 在装载器需要被创建时执行此方法,这里只有一个装载器,所以我们不必关心装载器的ID */ @Override public Loader<List<TrackInfo>> onCreateLoader(int id, Bundle args) { Log.i(TAG, "onCreateLoader"); // 数据库查询条件子句 // StringBuffer select = new StringBuffer("(" + Media.DATA // + " like'%.mp3' or " + Media.DATA + " like'%.wma')"); StringBuffer select = new StringBuffer(" 1=1 "); // 检查系统设置,是否需要按文件大小过滤 if (mSystemPreferences.getBoolean(SettingFragment.KEY_FILTER_BY_SIZE, true)) { // 查询语句:检索出.mp3为后缀名,时长大于1分钟,文件大小大于1MB的媒体文件 select.append(" and " + Media.SIZE + " > " + Constant.FILTER_SIZE); } // 检查系统设置,是否需要按歌曲时长过滤 if (mSystemPreferences.getBoolean( SettingFragment.KEY_FILTER_BY_DURATION, true)) { select.append(" and " + Media.DURATION + " > " + Constant.FILTER_DURATION); } if (mArtistInfo != null) { select.append(" and " + Media.ARTIST + " = '" + mArtistInfo.getArtistName() + "'"); } else if (mFolderInfo != null) { select.append(" and " + Media.DATA + " like '" + mFolderInfo.getFolderPath() + File.separator + "%'"); } else if (mPlaylistInfo != null) { select.append(" and " + Media._ID + " in (select " + Playlists.Members.AUDIO_ID + " from audio_playlists_map where " + Playlists.Members.PLAYLIST_ID + "=" + mPlaylistInfo.getId() + ")"); } else if (mAlbumInfo != null) { select.append(" and " + Media.ALBUM_ID + " = " + mAlbumInfo.getAlbumId()); } MusicRetrieveLoader loader = new MusicRetrieveLoader(getActivity(), select.toString(), null, mSortOrder); if (mFolderInfo != null) { loader.setFolderFilterPattern(mFolderInfo.getFolderPath()); } // 创建并返回一个Loader return loader; } @Override public void onLoadFinished(Loader<List<TrackInfo>> loader, List<TrackInfo> data) { Log.i(TAG, "onLoadFinished"); mHasNewData = true; mOriginalData.clear(); mOriginalData.addAll(data); mShowData.clear(); mShowData.addAll(data); if (mSortOrder.equals(Media.TITLE_KEY)) { Collections.sort(data, mTrackNameComparator); } else if (mSortOrder.equals(Media.ARTIST_KEY)) { Collections.sort(data, mArtistNameComparator); } mView_ListView.setEmptyView(mView_EmptyNoSong); if (data.size() == 0) { mView_TrackOperations.setVisibility(View.GONE); mView_MoreFunctions.setClickable(false); } else { mView_TrackOperations.setVisibility(View.VISIBLE); mView_MoreFunctions.setClickable(true); } mAdapter.setData(data); // 每次加载新的数据设置一下标题中的歌曲数目 if (getArguments() != null) { switch (getArguments().getInt(Constant.PARENT)) { case Constant.START_FROM_LOCAL_MUSIC: mView_Title.setText(getResources().getString( R.string.local_music) + "(" + data.size() + ")"); break; case Constant.START_FROM_ARTIST: mView_Title.setText(mArtistInfo.getArtistName() + "(" + data.size() + ")"); break; case Constant.START_FROM_FOLER: mView_Title.setText(mFolderInfo.getFolderName() + "(" + data.size() + ")"); break; case Constant.START_FROM_PLAYLIST: mView_Title.setText(mPlaylistInfo.getPlaylistName() + "(" + data.size() + ")"); break; case Constant.START_FROM_ALBUM: mView_Title.setText(mAlbumInfo.getAlbumName() + "(" + data.size() + ")"); break; default: break; } } if (mCurrentPlayInfo != null) { initCurrentPlayInfo(mCurrentPlayInfo); } } /** 此方法在提供给onLoadFinished()最后的一个游标准备关闭时调用,我们要确保不再使用它 */ @Override public void onLoaderReset(Loader<List<TrackInfo>> loader) { Log.i(TAG, "onLoaderReset"); mAdapter.setData(null); mView_TrackOperations.setVisibility(View.GONE); mView_MoreFunctions.setClickable(false); } /** 初始化当前播放信息 */ private void initCurrentPlayInfo(Bundle bundle) { mPlayingTrack = bundle.getParcelable(Constant.PLAYING_MUSIC_ITEM); if (mPlayingTrack != null) { mAdapter.setSpecifiedIndicator(MusicService.seekPosInListById( mAdapter.getData(), mPlayingTrack.getId())); } else { mAdapter.setSpecifiedIndicator(-1); } } /** 处理从启动处传递过来的参数 */ private void handleArguments() { // 如果有谁传递数据过来了,就设置一下 Bundle args = getArguments(); if (args != null) { switch (args.getInt(Constant.PARENT)) { case Constant.START_FROM_ARTIST: // 如果是从歌手列表里启动的 mArtistInfo = args.getParcelable(ArtistInfo.class .getSimpleName()); if (mArtistInfo != null) { // 更新标题 if (!mArtistInfo.getArtistName().equals("<unknown>")) { mView_Title.setText(mArtistInfo.getArtistName() + "(" + mArtistInfo.getNumberOfTracks() + ")"); } else { mView_Title.setText(getResources().getString( R.string.unknown_artist) + "(" + mArtistInfo.getNumberOfTracks() + ")"); } setTitleLeftDrawable(); } break; case Constant.START_FROM_FOLER: // 如果是从文件夹列表里启动的 mFolderInfo = args.getParcelable(FolderInfo.class .getSimpleName()); if (mFolderInfo != null) { // 更新标题 mView_Title.setText(mFolderInfo.getFolderName() + "(" + mFolderInfo.getNumOfTracks() + ")"); setTitleLeftDrawable(); } break; case Constant.START_FROM_PLAYLIST: // 如果是从播放列表里启动的 mPlaylistInfo = args.getParcelable(PlaylistInfo.class .getSimpleName()); if (mPlaylistInfo != null) { // 更新标题 mView_Title.setText(mPlaylistInfo.getPlaylistName() + "(" + mPlaylistInfo.getNumOfMembers() + ")"); setTitleLeftDrawable(); } break; case Constant.START_FROM_ALBUM: // 如果是从专辑列表里启动的 mAlbumInfo = args .getParcelable(AlbumInfo.class.getSimpleName()); if (mAlbumInfo != null) { // 更新标题 mView_Title.setText(mAlbumInfo.getAlbumName() + "(" + mAlbumInfo.getNumberOfSongs() + ")"); setTitleLeftDrawable(); } break; default: break; } } } private void setTitleLeftDrawable() { mView_Title.setClickable(true); Drawable title_drawable = getResources().getDrawable( R.drawable.btn_titile_back); title_drawable.setBounds(0, 0, title_drawable.getIntrinsicWidth(), title_drawable.getIntrinsicHeight()); mView_Title.setCompoundDrawables(title_drawable, null, null, null); mView_Title.setBackgroundResource(R.drawable.button_backround_light); } // 处理搜索的相关函数------------------------------------------------------------------ /** T9键盘各数字键对应的正则表达式 */ private static String T9KEYS[] = { "", "", "[abc]", "[def]", "[ghi]", "[jkl]", "[mno]", "[pqrs]", "[tuv]", "[wxyz]" }; /** 在搜索输入框末尾追加T9键的输入 */ private void appendImageSpan(int drawableResId, int keynum) { Drawable drawable = getResources().getDrawable(drawableResId); String insteadString = String.valueOf(keynum); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); // 需要处理的文本,[smile]是需要被替代的文本 SpannableString spannable = new SpannableString(insteadString); // 要让图片替代指定的文字就要用ImageSpan ImageSpan span = new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM); // 开始替换,注意第2和第3个参数表示从哪里开始替换到哪里替换结束(start和end) // 最后一个参数类似数学中的集合,[5,12)表示从5到12,包括5但不包括12 spannable.setSpan(span, 0, insteadString.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); Editable et = mView_SearchInput.getText(); int start = mView_SearchInput.getSelectionStart(); et.insert(start, spannable); mView_SearchInput.setText(et); mView_SearchInput.setSelection(start + spannable.length()); } /** 回退删除搜索框的T9键的输入 */ private void backDeleteImageSpan() { Editable et = mView_SearchInput.getText(); if (!et.toString().equals("")) { et = et.delete(et.length() - 1, et.length()); mView_SearchInput.setText(et); mView_SearchInput.setSelection(et.length()); } } /** * T9键盘简拼、全拼搜索 * * @param str * 输入的字符串,均为2~9的数字 */ private void pinyinSearch(String input) { mShowData.clear(); StringBuffer sb = new StringBuffer(); // XXX 对特殊非字母、非数字、非汉字的字符支持不理想,有待改进 // 获取每一个数字对应的字母列表并以'-'隔开 for (int i = 0; i < input.length(); i++) { if (mIsT9Keyboard && input.charAt(i) <= '9' && input.charAt(i) >= '0') { sb.append(T9KEYS[input.charAt(i) - '0']); } else { sb.append(input.charAt(i)); } if (i != input.length() - 1) { sb.append("-"); } } // 遍历原始数据集合,寻找匹配的条目 for (TrackInfo item : mOriginalData) { if (contains(sb.toString(), item.getTitleKey(), input)) { mShowData.add(item); } else if (contains(sb.toString(), item.getArtistKey(), input)) { mShowData.add(item); } } mAdapter.setData(mShowData); } /** * 检查所给的搜索索引值是否匹配给定正则表达式 * * @param regexp * 正则表达式 * @param key * 索引值 * @param input * 搜索条件是否大于6个字符 * @return */ private boolean contains(String regexp, String key, String input) { if (TextUtils.isEmpty(key)) { return false; } // 搜索条件大于6个字符将不按拼音首字母查询 if (input.length() < 6) { // 根据首字母进行模糊查询 Pattern pattern = Pattern.compile(regexp.toUpperCase().replace("-", "[*+a-z]*")); Matcher matcher = pattern.matcher(key); if (matcher.find()) { return true; } } // 根据全拼查询 Pattern pattern = Pattern.compile(regexp.replace("-", ""), Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(key); return matcher.find(); } 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_TrackOperations.setVisibility(View.GONE); mView_MoreFunctions.setClickable(false); mView_Title.setText(""); mView_ListView.setEmptyView(mView_EmptyNoStorage); 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_ListView.setEmptyView(mView_EmptyLoading); TrackBrowserFragment.this.getLoaderManager().restartLoader( MUSIC_RETRIEVE_LOADER, null, TrackBrowserFragment.this); } } }; // 删除提醒对话框处理------------------------------------------------------------------ private DialogInterface.OnClickListener mDeletePromptListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { boolean isDeleted = false; switch (getArguments().getInt(Constant.PARENT)) { case Constant.START_FROM_PLAYLIST: // 从播放列表移除歌曲,不会删除文件 isDeleted = PlaylistDAO.removeTrackFromPlaylist(getActivity() .getContentResolver(), mPlaylistInfo.getId(), new long[] { mToDeleteTrack.getId() }); if (isDeleted) { // 提示删除成功 Toast.makeText(getActivity(), getResources().getString(R.string.remove_success), Toast.LENGTH_SHORT).show(); } break; default: // 删除的歌曲现在是否正在播放 TrackInfo curTrack = mMusicServiceBinder.getCurrentPlayInfo() .getParcelable(Constant.PLAYING_MUSIC_ITEM); if (curTrack != null) { if (curTrack.getId() == mToDeleteTrack.getId()) { // 要删除的歌曲正在播放,则先播放下一首歌,如果没有下一首就停止播放 mMusicServiceBinder .removeSongFromCurrenPlaylist(mToDeleteTrack .getId()); } } // 删除指定的歌曲,在存储器上的文件和数据库里的记录都要删除 PlaylistDAO.removeTrackFromDatabase(getActivity() .getContentResolver(), new long[] { mToDeleteTrack .getId() }); isDeleted = PlaylistDAO.deleteFile(mToDeleteTrack.getData()); if (isDeleted) { // 提示删除成功 Toast.makeText(getActivity(), getResources().getString(R.string.delete_success), Toast.LENGTH_SHORT).show(); } break; } if (!isDeleted) { // 删除失败,提示失败信息 Toast.makeText(getActivity(), getResources().getString(R.string.delete_failed), Toast.LENGTH_SHORT).show(); } else { // 重新读取数据库,更新列表显示 getLoaderManager().restartLoader(MUSIC_RETRIEVE_LOADER, null, TrackBrowserFragment.this); } } }; private OnPlaybackStateChangeListener mOnPlaybackStateChangeListener = new OnPlaybackStateChangeListener() { @Override public void onMusicPlayed() { } @Override public void onMusicPaused() { } @Override public void onMusicStopped() { } @Override public void onPlayNewSong(TrackInfo playingSong) { mPlayingTrack = playingSong; mAdapter.setSpecifiedIndicator(MusicService.seekPosInListById( mAdapter.getData(), playingSong.getId())); } @Override public void onPlayModeChanged(int playMode) { } @Override public void onPlayProgressUpdate(int currentMillis) { } }; // 按歌曲名称顺序排序 private Comparator<TrackInfo> mTrackNameComparator = new Comparator<TrackInfo>() { char first_l, first_r; @Override public int compare(TrackInfo lhs, TrackInfo rhs) { first_l = lhs.getTitleKey().charAt(0); first_r = rhs.getTitleKey().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; } } }; // 按歌曲名称顺序排序 private Comparator<TrackInfo> mArtistNameComparator = new Comparator<TrackInfo>() { char first_l, first_r; @Override public int compare(TrackInfo lhs, TrackInfo rhs) { first_l = lhs.getArtistKey().charAt(0); first_r = rhs.getArtistKey().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; } } }; }