/* * Name : MultiTrackChoiceActivity.java * Author : zbk * Copyright : Copyright (c) * Description : MultiTrackChoiceActivity.java - * Review : */ package com.android.music; import android.app.ListActivity; import android.content.AsyncQueryHandler; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.database.CharArrayBuffer; import android.database.Cursor; import android.media.AudioManager; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.provider.MediaStore; import android.util.Log; import android.util.SparseBooleanArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.Button; import android.widget.CheckBox; import android.widget.CursorAdapter; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.AdapterView.OnItemClickListener; /** * This activity provides a list view for all of the music . */ public class MultiTrackChoiceActivity extends ListActivity implements OnItemClickListener { private static final String LOGTAG = "MultiTrackChoiceActivity"; private String mSortOrder; private String[] mCursorCols; private boolean mAdapterSent = false; private TrackListAdapter mAdapter; private Cursor mTrackCursor; private CheckBox all; private Button btnAdd; private Button btnCancel; private Button btnCheckAll; private TextView checkBoxTitle; // private LinearLayout linear; // private ListView lv; private RelativeLayout rl; private String mPlaylist; @Override protected void onCreate(Bundle icicle) { Log.d(LOGTAG,"Activity create start"); super.onCreate(icicle); requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); Intent intent = getIntent(); setVolumeControlStream(AudioManager.STREAM_MUSIC); if (icicle != null) { mPlaylist = icicle.getString("playlist"); } else { mPlaylist = intent.getStringExtra("playlist"); } setContentView(R.layout.multi_track_choice); mAdapter = (TrackListAdapter) getLastNonConfigurationInstance(); if (mAdapter != null) { mAdapter.setActivity(this); setListAdapter(mAdapter); } IntentFilter f = new IntentFilter(); f.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED); f.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED); f.addAction(Intent.ACTION_MEDIA_UNMOUNTED); f.addDataScheme("file"); registerReceiver(mScanListener, f); if (mAdapter == null) { mAdapter = new TrackListAdapter( getApplication(), // need to use application context to avoid leaks this, null); setListAdapter(mAdapter); getTrackCursor(mAdapter.getQueryHandler()); } mCursorCols = new String[] { MediaStore.Audio.Media._ID, MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.ALBUM, MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ARTIST_ID, MediaStore.Audio.Media.DURATION }; initializeViews(); Log.d(LOGTAG,"Activity create end"); } /** * Initialize all the controls. */ private void initializeViews() { all = (CheckBox) findViewById(R.id.checkbox_selected_all); all.setOnClickListener(new OnClickListener() { public void onClick(View v) { for (int i = 0; i < mAdapter.getCount(); i++) { mAdapter.setChecked(i, all.isChecked()); } mAdapter.notifyDataSetChanged(); } }); btnCheckAll = (Button) findViewById(R.id.btn_checkall); btnCheckAll.setOnClickListener(new OnClickListener() { public void onClick(View v) { all.setChecked(!all.isChecked()); for (int i = 0; i < mAdapter.getCount(); i++) { mAdapter.setChecked(i, all.isChecked()); } mAdapter.notifyDataSetChanged(); } }); btnAdd = (Button) findViewById(R.id.AddButton); btnAdd.setOnClickListener(new OnClickListener() { public void onClick(View v) { long[] ids = mAdapter.getCheckedIdArray(); if (mPlaylist != null) { if (mPlaylist.equals("nowplaying")) { MusicUtils.addToCurrentPlaylist( MultiTrackChoiceActivity.this, ids); } else { long playlist = Long.valueOf(mPlaylist); MusicUtils.addToPlaylist( MultiTrackChoiceActivity.this, ids, playlist); } Intent intent = new Intent(Intent.ACTION_EDIT); intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/tracklist"); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.putExtra("playlist", mPlaylist); startActivity(intent); finish(); } } }); btnCancel = (Button) findViewById(R.id.CancelButton); btnCancel.setOnClickListener(new OnClickListener() { public void onClick(View v) { finish(); } }); checkBoxTitle = (TextView) findViewById(R.id.CheckBoxTitle); // linear = (LinearLayout) findViewById(R.id.ButtonLinearLayout); // lv=(ListView)findViewById(android.R.id.list); rl=(RelativeLayout)findViewById(R.id.CheckboxLinearLayout); } @Override public Object onRetainNonConfigurationInstance() { TrackListAdapter a = mAdapter; mAdapterSent = true; return a; } @Override public void onResume() { Log.d(LOGTAG,"Activity resumed start"); super.onResume(); if (mTrackCursor != null) { getListView().invalidateViews(); } MusicUtils.setSpinnerState(this); Log.d(LOGTAG,"Activity resumed end"); } @Override public void onPause() { Log.d(LOGTAG,"Activity pause start"); mReScanHandler.removeCallbacksAndMessages(null); super.onPause(); Log.d(LOGTAG,"Activity pause end"); } public void onSaveInstanceState(Bundle outcicle) { outcicle.putString("playlist", mPlaylist); super.onSaveInstanceState(outcicle); } @Override public void onDestroy() { Log.d(LOGTAG,"Activity destroy start"); // If we have an adapter and didn't send it off to another activity yet, we should // close its cursor, which we do by assigning a null cursor to it. Doing this // instead of closing the cursor directly keeps the framework from accessing // the closed cursor later. if (!mAdapterSent && mAdapter != null) { mAdapter.changeCursor(null); } // Because we pass the adapter to the next activity, we need to make // sure it doesn't keep a reference to this activity. We can do this // by clearing its DatasetObservers, which setListAdapter(null) does. setListAdapter(null); mAdapter = null; unregisterReceiverSafe(mScanListener); super.onDestroy(); Log.d(LOGTAG,"Activity destroy end"); } /** * 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 } } private void getTrackCursor(TrackListAdapter.TrackQueryHandler queryhandler) { if (queryhandler == null) { throw new IllegalArgumentException(); } mSortOrder = MediaStore.Audio.Media.TITLE_KEY; StringBuilder where = new StringBuilder(); where.append(MediaStore.Audio.Media.TITLE + " != ''"); where.append(" AND " + MediaStore.Audio.Media.IS_MUSIC + "=1"); Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; queryhandler.doQuery(uri, mCursorCols, where.toString(), null, mSortOrder); } /* * This listener gets called when the media scanner starts up or finishes, and * when the sd card is unmounted. */ private BroadcastReceiver mScanListener = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (Intent.ACTION_MEDIA_SCANNER_STARTED.equals(action) || Intent.ACTION_MEDIA_SCANNER_FINISHED.equals(action)) { MusicUtils.setSpinnerState(MultiTrackChoiceActivity.this); } mReScanHandler.sendEmptyMessage(0); } }; private Handler mReScanHandler = new Handler() { @Override public void handleMessage(Message msg) { if (mAdapter != null) { getTrackCursor(mAdapter.getQueryHandler()); } } }; @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { mAdapter.setChecked(position, !mAdapter.isChecked(position)); if (mAdapter.getCheckedCount() == mAdapter.getCount()) { all.setChecked(true); } else { all.setChecked(false); } mAdapter.notifyDataSetChanged(); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { mAdapter.setChecked(position, !mAdapter.isChecked(position)); if (mAdapter.getCheckedCount() == mAdapter.getCount()) { all.setChecked(true); } else { all.setChecked(false); } mAdapter.notifyDataSetChanged(); } public void init(Cursor newCursor, boolean isLimited) { if (mAdapter == null) { return; } mAdapter.changeCursor(newCursor); // also sets mTrackCursor if (mTrackCursor == null) { //MusicUtils.displayDatabaseError(MultiTrackChoiceActivity.this); closeContextMenu(); all.setVisibility(View.GONE); btnCheckAll.setVisibility(View.GONE); //linear.setVisibility(View.GONE); btnAdd.setVisibility(View.GONE); btnCancel.setVisibility(View.GONE); checkBoxTitle.setVisibility(View.GONE); // lv.setVisibility(View.GONE); rl.setVisibility(View.GONE); mReScanHandler.sendEmptyMessageDelayed(0, 1000); } else { MusicUtils.hideDatabaseError(MultiTrackChoiceActivity.this); all.setVisibility(View.VISIBLE); btnCheckAll.setVisibility(View.VISIBLE); //linear.setVisibility(View.VISIBLE); btnAdd.setVisibility(View.VISIBLE); btnCancel.setVisibility(View.VISIBLE); checkBoxTitle.setVisibility(View.VISIBLE); // lv.setVisibility(View.VISIBLE); rl.setVisibility(View.VISIBLE); } } static class TrackListAdapter extends CursorAdapter { int mTitleIdx; int mArtistIdx; int mDurationIdx; int mAudioIdIdx; private final StringBuilder mBuilder = new StringBuilder(); private final String mUnknownArtist; private LayoutInflater mInflater; private MultiTrackChoiceActivity mActivity = null; private TrackQueryHandler mQueryHandler; static class ViewHolder { TextView line1; TextView line2; TextView duration; CheckBox checkbox; CharArrayBuffer buffer1; char [] buffer2; } class TrackQueryHandler extends AsyncQueryHandler { class QueryArgs { public Uri uri; public String [] projection; public String selection; public String [] selectionArgs; public String orderBy; } TrackQueryHandler(ContentResolver res) { super(res); } public void doQuery(Uri uri, String[] projection, String selection, String[] selectionArgs, String orderBy) { // Get 100 results first, which is enough to allow the user to start scrolling, // while still being very fast. Uri limituri = uri.buildUpon().appendQueryParameter("limit", "100").build(); QueryArgs args = new QueryArgs(); args.uri = uri; args.projection = projection; args.selection = selection; args.selectionArgs = selectionArgs; args.orderBy = orderBy; startQuery(0, args, limituri, projection, selection, selectionArgs, orderBy); } @Override protected void onQueryComplete(int token, Object cookie, Cursor cursor) { mActivity.init(cursor, cookie != null); if (token == 0 && cookie != null && cursor != null && cursor.getCount() >= 100) { QueryArgs args = (QueryArgs) cookie; startQuery(1, null, args.uri, args.projection, args.selection, args.selectionArgs, args.orderBy); } } } TrackListAdapter(Context context, MultiTrackChoiceActivity currentactivity, Cursor cursor) { super(context, cursor); mInflater = LayoutInflater.from(context); mActivity = currentactivity; getColumnIndices(cursor); mUnknownArtist = context.getString(R.string.unknown_artist_name); mQueryHandler = new TrackQueryHandler(context.getContentResolver()); } public void setActivity(MultiTrackChoiceActivity newactivity) { mActivity = newactivity; } public TrackQueryHandler getQueryHandler() { return mQueryHandler; } private void getColumnIndices(Cursor cursor) { if (cursor != null) { mTitleIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE); mArtistIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST); mDurationIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION); try { mAudioIdIdx = cursor.getColumnIndexOrThrow( MediaStore.Audio.Playlists.Members.AUDIO_ID); } catch (IllegalArgumentException ex) { mAudioIdIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID); } } } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { return null; } @Override public void bindView(View view, Context context, Cursor cursor) { return; } public View getView(final int position, View convertView, ViewGroup parent) { ViewHolder vh = new ViewHolder(); if (convertView == null) { convertView = mInflater.inflate(R.layout.multi_track_choice_list, null); } vh.line1 = (TextView) convertView.findViewById(R.id.line1); vh.line2 = (TextView) convertView.findViewById(R.id.line2); vh.duration = (TextView) convertView.findViewById(R.id.duration); vh.checkbox = (CheckBox) convertView.findViewById(R.id.music_checkbox_selected); vh.buffer1 = new CharArrayBuffer(100); vh.buffer2 = new char[200]; final Cursor cursor = (Cursor) getItem(position); cursor.copyStringToBuffer(mTitleIdx, vh.buffer1); vh.line1.setText(vh.buffer1.data, 0, vh.buffer1.sizeCopied); int secs = cursor.getInt(mDurationIdx) / 1000; if (secs == 0) { vh.duration.setText(""); } else { vh.duration.setText(MusicUtils.makeTimeString(convertView.getContext(), secs)); } vh.checkbox.setVisibility(View.VISIBLE); vh.checkbox.setChecked(isChecked(position)); vh.checkbox.setClickable(false); final StringBuilder builder = mBuilder; builder.delete(0, builder.length()); String name = cursor.getString(mArtistIdx); if (name == null || name.equals(MediaStore.UNKNOWN_STRING)) { builder.append(mUnknownArtist); } else { builder.append(name); } int len = builder.length(); if (vh.buffer2.length < len) { vh.buffer2 = new char[len]; } builder.getChars(0, len, vh.buffer2, 0); vh.line2.setText(vh.buffer2, 0, len); convertView.setTag(getItemId(position)); return convertView; } @Override public void changeCursor(Cursor cursor) { if (mActivity.isFinishing() && cursor != null) { cursor.close(); cursor = null; } if (cursor != mActivity.mTrackCursor) { mActivity.mTrackCursor = cursor; super.changeCursor(cursor); getColumnIndices(cursor); } } private SparseBooleanArray mCheckArray = new SparseBooleanArray(); private int mCheckCount = 0; public long[] getCheckedIdArray(){ long[] ids = new long[mCheckCount]; int pos = 0; for (int i = getCount() - 1; i >= 0; i--) { if (isChecked(i)) { ids[pos++] = getItemId(i); } } return ids; } public boolean hasCheckedItem() { return mCheckCount > 0; } public boolean isChecked(int position){ int id = (int) getItemId(position); return mCheckArray.get(id); } public int getCheckedCount(){ return mCheckCount; } public void setChecked(int position, boolean checked){ int id = (int) getItemId(position); boolean checked_before = isChecked(position); if (checked_before != checked) { mCheckCount += checked ? 1 : -1; } mCheckArray.put(id, checked); } } }