1792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project/*
2792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *
4792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * you may not use this file except in compliance with the License.
6792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * You may obtain a copy of the License at
7792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *
8792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *
10792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * See the License for the specific language governing permissions and
14792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * limitations under the License.
15792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */
16792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
17792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectpackage com.android.music;
18792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
19792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.app.Activity;
20792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.ComponentName;
21792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.ContentResolver;
22792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.ContentUris;
23792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.ContentValues;
24792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.Context;
25f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissenimport android.content.ContextWrapper;
26792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.Intent;
27792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.ServiceConnection;
28792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.SharedPreferences;
29792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.SharedPreferences.Editor;
30792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.res.Resources;
31792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.database.Cursor;
32792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.graphics.Bitmap;
33792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.graphics.BitmapFactory;
34792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.graphics.Canvas;
35792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.graphics.ColorFilter;
363193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissenimport android.graphics.ColorMatrix;
373193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissenimport android.graphics.ColorMatrixColorFilter;
383193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissenimport android.graphics.Matrix;
393193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissenimport android.graphics.Paint;
40792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.graphics.PixelFormat;
41792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.graphics.drawable.BitmapDrawable;
42792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.graphics.drawable.Drawable;
43792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.net.Uri;
44792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.Environment;
45792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.ParcelFileDescriptor;
467a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissenimport android.os.RemoteException;
47792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.provider.MediaStore;
48792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.provider.Settings;
497a05298d5af6f796f3a260fa60b11d1c029b4207Marco Nelissenimport android.text.TextUtils;
503988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissenimport android.text.format.Time;
51792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.util.Log;
52ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissenimport android.view.Menu;
53ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissenimport android.view.MenuItem;
54792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.view.SubMenu;
55792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.view.View;
56792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.view.Window;
57ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissenimport android.widget.TabWidget;
58792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.widget.TextView;
59792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.widget.Toast;
60792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
617a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissenimport java.io.File;
627a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissenimport java.io.FileDescriptor;
637a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissenimport java.io.FileNotFoundException;
647a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissenimport java.io.IOException;
657a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissenimport java.io.InputStream;
663988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissenimport java.io.PrintWriter;
677a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissenimport java.util.Arrays;
687a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissenimport java.util.Formatter;
697a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissenimport java.util.HashMap;
707a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissenimport java.util.Locale;
717a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen
72792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectpublic class MusicUtils {
73792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
74792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final String TAG = "MusicUtils";
75792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
76792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public interface Defs {
77792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public final static int OPEN_URL = 0;
78792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public final static int ADD_TO_PLAYLIST = 1;
79792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public final static int USE_AS_RINGTONE = 2;
80792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public final static int PLAYLIST_SELECTED = 3;
81792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public final static int NEW_PLAYLIST = 4;
82792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public final static int PLAY_SELECTION = 5;
83792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public final static int GOTO_START = 6;
84792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public final static int GOTO_PLAYBACK = 7;
85792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public final static int PARTY_SHUFFLE = 8;
86792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public final static int SHUFFLE_ALL = 9;
87792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public final static int DELETE_ITEM = 10;
88792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public final static int SCAN_DONE = 11;
89792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public final static int QUEUE = 12;
90f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen        public final static int EFFECTS_PANEL = 13;
91f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen        public final static int CHILD_MENU_BASE = 14; // this should be the last item
92792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
93792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
94792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static String makeAlbumsLabel(Context context, int numalbums, int numsongs, boolean isUnknown) {
95792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // There are two formats for the albums/songs information:
96792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // "N Song(s)"  - used for unknown artist/album
97792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // "N Album(s)" - used for known albums
98792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
99792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        StringBuilder songs_albums = new StringBuilder();
100792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
101792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Resources r = context.getResources();
102792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (isUnknown) {
103792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (numsongs == 1) {
104792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                songs_albums.append(context.getString(R.string.onesong));
105792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
106792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String f = r.getQuantityText(R.plurals.Nsongs, numsongs).toString();
107792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                sFormatBuilder.setLength(0);
108792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                sFormatter.format(f, Integer.valueOf(numsongs));
109792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                songs_albums.append(sFormatBuilder);
110792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
111792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else {
112792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String f = r.getQuantityText(R.plurals.Nalbums, numalbums).toString();
113792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            sFormatBuilder.setLength(0);
114792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            sFormatter.format(f, Integer.valueOf(numalbums));
115792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            songs_albums.append(sFormatBuilder);
116792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            songs_albums.append(context.getString(R.string.albumsongseparator));
117792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
118792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return songs_albums.toString();
119792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
120792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
121792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
122792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * This is now only used for the query screen
123792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
124792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static String makeAlbumsSongsLabel(Context context, int numalbums, int numsongs, boolean isUnknown) {
125792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // There are several formats for the albums/songs information:
126792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // "1 Song"   - used if there is only 1 song
127792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // "N Songs" - used for the "unknown artist" item
128792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // "1 Album"/"N Songs"
129792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // "N Album"/"M Songs"
130792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Depending on locale, these may need to be further subdivided
131792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
132792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        StringBuilder songs_albums = new StringBuilder();
133792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
134792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (numsongs == 1) {
135792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            songs_albums.append(context.getString(R.string.onesong));
136792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else {
137792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Resources r = context.getResources();
138792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (! isUnknown) {
139792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String f = r.getQuantityText(R.plurals.Nalbums, numalbums).toString();
140792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                sFormatBuilder.setLength(0);
141792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                sFormatter.format(f, Integer.valueOf(numalbums));
142792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                songs_albums.append(sFormatBuilder);
143792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                songs_albums.append(context.getString(R.string.albumsongseparator));
144792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
145792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String f = r.getQuantityText(R.plurals.Nsongs, numsongs).toString();
146792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            sFormatBuilder.setLength(0);
147792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            sFormatter.format(f, Integer.valueOf(numsongs));
148792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            songs_albums.append(sFormatBuilder);
149792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
150792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return songs_albums.toString();
151792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
152792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
153792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static IMediaPlaybackService sService = null;
154792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static HashMap<Context, ServiceBinder> sConnectionMap = new HashMap<Context, ServiceBinder>();
155792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
156f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen    public static class ServiceToken {
157f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        ContextWrapper mWrappedContext;
158f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        ServiceToken(ContextWrapper context) {
159f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen            mWrappedContext = context;
160f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        }
161f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen    }
162f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen
1633b55356662437499c38418629a38c8fb08880302Marco Nelissen    public static ServiceToken bindToService(Activity context) {
164792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return bindToService(context, null);
165792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
166792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1673b55356662437499c38418629a38c8fb08880302Marco Nelissen    public static ServiceToken bindToService(Activity context, ServiceConnection callback) {
1683b55356662437499c38418629a38c8fb08880302Marco Nelissen        Activity realActivity = context.getParent();
1693b55356662437499c38418629a38c8fb08880302Marco Nelissen        if (realActivity == null) {
1703b55356662437499c38418629a38c8fb08880302Marco Nelissen            realActivity = context;
1713b55356662437499c38418629a38c8fb08880302Marco Nelissen        }
1723b55356662437499c38418629a38c8fb08880302Marco Nelissen        ContextWrapper cw = new ContextWrapper(realActivity);
173f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        cw.startService(new Intent(cw, MediaPlaybackService.class));
174792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ServiceBinder sb = new ServiceBinder(callback);
175f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        if (cw.bindService((new Intent()).setClass(cw, MediaPlaybackService.class), sb, 0)) {
176f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen            sConnectionMap.put(cw, sb);
177f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen            return new ServiceToken(cw);
178f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        }
1793b55356662437499c38418629a38c8fb08880302Marco Nelissen        Log.e("Music", "Failed to bind to service");
180f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        return null;
181792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
182f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen
183f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen    public static void unbindFromService(ServiceToken token) {
1843b55356662437499c38418629a38c8fb08880302Marco Nelissen        if (token == null) {
1853b55356662437499c38418629a38c8fb08880302Marco Nelissen            Log.e("MusicUtils", "Trying to unbind with null token");
1863b55356662437499c38418629a38c8fb08880302Marco Nelissen            return;
1873b55356662437499c38418629a38c8fb08880302Marco Nelissen        }
188f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        ContextWrapper cw = token.mWrappedContext;
189f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        ServiceBinder sb = sConnectionMap.remove(cw);
190792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (sb == null) {
191792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Log.e("MusicUtils", "Trying to unbind for unknown Context");
192792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return;
193792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
194f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        cw.unbindService(sb);
195792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (sConnectionMap.isEmpty()) {
196792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // presumably there is nobody interested in the service at this point,
197792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // so don't hang on to the ServiceConnection
198792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            sService = null;
199792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
200792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
201792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
202792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static class ServiceBinder implements ServiceConnection {
203792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ServiceConnection mCallback;
204792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ServiceBinder(ServiceConnection callback) {
205792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCallback = callback;
206792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
207792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
208792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void onServiceConnected(ComponentName className, android.os.IBinder service) {
209792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            sService = IMediaPlaybackService.Stub.asInterface(service);
210792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            initAlbumArtCache();
211792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCallback != null) {
212792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mCallback.onServiceConnected(className, service);
213792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
214792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
215792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
216792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void onServiceDisconnected(ComponentName className) {
217792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCallback != null) {
218792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mCallback.onServiceDisconnected(className);
219792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
220792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            sService = null;
221792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
222792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
223792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
224bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public static long getCurrentAlbumId() {
225792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (sService != null) {
226792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            try {
227792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return sService.getAlbumId();
228792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (RemoteException ex) {
229792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
230792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
231792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
232792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
233792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
234bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public static long getCurrentArtistId() {
235792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (MusicUtils.sService != null) {
236792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            try {
237792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return sService.getArtistId();
238792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (RemoteException ex) {
239792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
240792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
241792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
242792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
243792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
244bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public static long getCurrentAudioId() {
245792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (MusicUtils.sService != null) {
246792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            try {
247792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return sService.getAudioId();
248792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (RemoteException ex) {
249792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
250792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
251792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
252792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
253792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
254792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static int getCurrentShuffleMode() {
255792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int mode = MediaPlaybackService.SHUFFLE_NONE;
256792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (sService != null) {
257792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            try {
258792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mode = sService.getShuffleMode();
259792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (RemoteException ex) {
260792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
261792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
262792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mode;
263792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
264792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
265ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen    public static void togglePartyShuffle() {
266ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        if (sService != null) {
267ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            int shuffle = getCurrentShuffleMode();
268ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            try {
269ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                if (shuffle == MediaPlaybackService.SHUFFLE_AUTO) {
270ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                    sService.setShuffleMode(MediaPlaybackService.SHUFFLE_NONE);
271ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                } else {
272ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                    sService.setShuffleMode(MediaPlaybackService.SHUFFLE_AUTO);
273ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                }
274ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            } catch (RemoteException ex) {
275ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            }
276ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        }
277ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen    }
278ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen
279ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen    public static void setPartyShuffleMenuIcon(Menu menu) {
280ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        MenuItem item = menu.findItem(Defs.PARTY_SHUFFLE);
281ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        if (item != null) {
282ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            int shuffle = MusicUtils.getCurrentShuffleMode();
283ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            if (shuffle == MediaPlaybackService.SHUFFLE_AUTO) {
284ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                item.setIcon(R.drawable.ic_menu_party_shuffle);
285ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                item.setTitle(R.string.party_shuffle_off);
286ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            } else {
287ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                item.setIcon(R.drawable.ic_menu_party_shuffle);
288ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                item.setTitle(R.string.party_shuffle);
289ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            }
290ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        }
291ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen    }
292ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen
293792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /*
294792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns true if a file is currently opened for playback (regardless
295792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * of whether it's playing or paused).
296792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
297792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static boolean isMusicLoaded() {
298792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (MusicUtils.sService != null) {
299792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            try {
300792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return sService.getPath() != null;
301792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (RemoteException ex) {
302792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
303792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
304792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return false;
305792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
306792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
307bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    private final static long [] sEmptyList = new long[0];
308f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen
309bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public static long [] getSongListForCursor(Cursor cursor) {
310792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (cursor == null) {
311792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return sEmptyList;
312792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
313792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int len = cursor.getCount();
314bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        long [] list = new long[len];
315792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        cursor.moveToFirst();
316792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int colidx = -1;
317792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
318792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            colidx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.Members.AUDIO_ID);
319792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } catch (IllegalArgumentException ex) {
320792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            colidx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID);
321792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
322792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        for (int i = 0; i < len; i++) {
323bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            list[i] = cursor.getLong(colidx);
324792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            cursor.moveToNext();
325792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
326792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return list;
327792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
328792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
329bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public static long [] getSongListForArtist(Context context, long id) {
330792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        final String[] ccols = new String[] { MediaStore.Audio.Media._ID };
331792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        String where = MediaStore.Audio.Media.ARTIST_ID + "=" + id + " AND " +
332792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        MediaStore.Audio.Media.IS_MUSIC + "=1";
333792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Cursor cursor = query(context, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
334792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ccols, where, null,
335792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                MediaStore.Audio.Media.ALBUM_KEY + ","  + MediaStore.Audio.Media.TRACK);
336792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
337792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (cursor != null) {
338bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long [] list = getSongListForCursor(cursor);
339792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            cursor.close();
340792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return list;
341792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
342792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return sEmptyList;
343792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
344792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
345bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public static long [] getSongListForAlbum(Context context, long id) {
346792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        final String[] ccols = new String[] { MediaStore.Audio.Media._ID };
347792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        String where = MediaStore.Audio.Media.ALBUM_ID + "=" + id + " AND " +
348792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                MediaStore.Audio.Media.IS_MUSIC + "=1";
349792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Cursor cursor = query(context, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
350792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ccols, where, null, MediaStore.Audio.Media.TRACK);
351792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
352792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (cursor != null) {
353bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long [] list = getSongListForCursor(cursor);
354792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            cursor.close();
355792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return list;
356792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
357792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return sEmptyList;
358792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
359792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
360bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public static long [] getSongListForPlaylist(Context context, long plid) {
361792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        final String[] ccols = new String[] { MediaStore.Audio.Playlists.Members.AUDIO_ID };
362792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Cursor cursor = query(context, MediaStore.Audio.Playlists.Members.getContentUri("external", plid),
363792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ccols, null, null, MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER);
364792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
365792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (cursor != null) {
366bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long [] list = getSongListForCursor(cursor);
367792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            cursor.close();
368792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return list;
369792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
370792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return sEmptyList;
371792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
372792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
373792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static void playPlaylist(Context context, long plid) {
374bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        long [] list = getSongListForPlaylist(context, plid);
375792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (list != null) {
376792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            playAll(context, list, -1, false);
377792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
378792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
379792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
380bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public static long [] getAllSongs(Context context) {
381792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Cursor c = query(context, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
382792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                new String[] {MediaStore.Audio.Media._ID}, MediaStore.Audio.Media.IS_MUSIC + "=1",
383792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                null, null);
384792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
385792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (c == null || c.getCount() == 0) {
386792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return null;
387792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
388792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = c.getCount();
389bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long [] list = new long[len];
390792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
391792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                c.moveToNext();
392bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                list[i] = c.getLong(0);
393792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
394792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
395792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return list;
396792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } finally {
397792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (c != null) {
398792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                c.close();
399792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
400792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
401792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
402792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
403792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
404792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Fills out the given submenu with items for "new playlist" and
405792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * any existing playlists. When the user selects an item, the
406792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * application will receive PLAYLIST_SELECTED with the Uri of
407792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the selected playlist, NEW_PLAYLIST if a new playlist
408792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * should be created, and QUEUE if the "current playlist" was
409792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * selected.
410792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param context The context to use for creating the menu items
411792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param sub The submenu to add the items to.
412792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
413792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static void makePlaylistMenu(Context context, SubMenu sub) {
414792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        String[] cols = new String[] {
415792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                MediaStore.Audio.Playlists._ID,
416792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                MediaStore.Audio.Playlists.NAME
417792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        };
418792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ContentResolver resolver = context.getContentResolver();
419792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (resolver == null) {
420792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            System.out.println("resolver = null");
421792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else {
422792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String whereclause = MediaStore.Audio.Playlists.NAME + " != ''";
423792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Cursor cur = resolver.query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
424792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                cols, whereclause, null,
425792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                MediaStore.Audio.Playlists.NAME);
426792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            sub.clear();
427792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            sub.add(1, Defs.QUEUE, 0, R.string.queue);
428792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            sub.add(1, Defs.NEW_PLAYLIST, 0, R.string.new_playlist);
429792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (cur != null && cur.getCount() > 0) {
430792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                //sub.addSeparator(1, 0);
431792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                cur.moveToFirst();
432792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                while (! cur.isAfterLast()) {
433792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    Intent intent = new Intent();
434bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                    intent.putExtra("playlist", cur.getLong(0));
435792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project//                    if (cur.getInt(0) == mLastPlaylistSelected) {
436792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project//                        sub.add(0, MusicBaseActivity.PLAYLIST_SELECTED, cur.getString(1)).setIntent(intent);
437792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project//                    } else {
438792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        sub.add(1, Defs.PLAYLIST_SELECTED, 0, cur.getString(1)).setIntent(intent);
439792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project//                    }
440792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    cur.moveToNext();
441792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
442792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
443792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (cur != null) {
444792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                cur.close();
445792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
446792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
447792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
448792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
449792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static void clearPlaylist(Context context, int plid) {
450792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
451792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", plid);
452792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        context.getContentResolver().delete(uri, null, null);
453792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return;
454792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
455792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
456bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public static void deleteTracks(Context context, long [] list) {
457792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
458792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        String [] cols = new String [] { MediaStore.Audio.Media._ID,
459792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.ALBUM_ID };
460792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        StringBuilder where = new StringBuilder();
461792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        where.append(MediaStore.Audio.Media._ID + " IN (");
462792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        for (int i = 0; i < list.length; i++) {
463792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            where.append(list[i]);
464792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (i < list.length - 1) {
465792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                where.append(",");
466792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
467792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
468792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        where.append(")");
469792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Cursor c = query(context, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, cols,
470792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                where.toString(), null, null);
471792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
472792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (c != null) {
473792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
474792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // step 1: remove selected tracks from the current playlist, as well
475792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // as from the album art cache
476792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            try {
477792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                c.moveToFirst();
478792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                while (! c.isAfterLast()) {
479792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // remove from current playlist
480bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                    long id = c.getLong(0);
481792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    sService.removeTrack(id);
482792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // remove from album art cache
483bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                    long artIndex = c.getLong(2);
484792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    synchronized(sArtCache) {
485792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        sArtCache.remove(artIndex);
486792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
487792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    c.moveToNext();
488792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
489792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (RemoteException ex) {
490792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
491792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
492792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // step 2: remove selected tracks from the database
493792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            context.getContentResolver().delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, where.toString(), null);
494792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
495792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // step 3: remove files from card
496792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            c.moveToFirst();
497792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            while (! c.isAfterLast()) {
498792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String name = c.getString(1);
499792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                File f = new File(name);
500792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                try {  // File.delete can throw a security exception
501792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (!f.delete()) {
502792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // I'm not sure if we'd ever get here (deletion would
503792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // have to fail, but no exception thrown)
504792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        Log.e("MusicUtils", "Failed to delete file " + name);
505792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
506792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    c.moveToNext();
507792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } catch (SecurityException ex) {
508792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    c.moveToNext();
509792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
510792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
511792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            c.close();
512792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
513792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
514792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        String message = context.getResources().getQuantityString(
515792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                R.plurals.NNNtracksdeleted, list.length, Integer.valueOf(list.length));
516792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
517792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
518792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // We deleted a number of tracks, which could affect any number of things
519792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // in the media content domain, so update everything.
520792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        context.getContentResolver().notifyChange(Uri.parse("content://media"), null);
521792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
522792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
523bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public static void addToCurrentPlaylist(Context context, long [] list) {
524792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (sService == null) {
525792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return;
526792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
527792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
528792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            sService.enqueue(list, MediaPlaybackService.LAST);
529792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String message = context.getResources().getQuantityString(
530792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    R.plurals.NNNtrackstoplaylist, list.length, Integer.valueOf(list.length));
531792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
532792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } catch (RemoteException ex) {
533792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
534792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
535f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen
536f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen    private static ContentValues[] sContentValuesCache = null;
537f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen
538f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen    /**
539f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen     * @param ids The source array containing all the ids to be added to the playlist
540f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen     * @param offset Where in the 'ids' array we start reading
541f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen     * @param len How many items to copy during this pass
542f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen     * @param base The play order offset to use for this pass
543f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen     */
544f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen    private static void makeInsertItems(long[] ids, int offset, int len, int base) {
545f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        // adjust 'len' if would extend beyond the end of the source array
546f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        if (offset + len > ids.length) {
547f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen            len = ids.length - offset;
548f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        }
549f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        // allocate the ContentValues array, or reallocate if it is the wrong size
550f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        if (sContentValuesCache == null || sContentValuesCache.length != len) {
551f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen            sContentValuesCache = new ContentValues[len];
552f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        }
553f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        // fill in the ContentValues array with the right values for this pass
554f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        for (int i = 0; i < len; i++) {
555f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen            if (sContentValuesCache[i] == null) {
556f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen                sContentValuesCache[i] = new ContentValues();
557f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen            }
558f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen
559f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen            sContentValuesCache[i].put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, base + offset + i);
560f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen            sContentValuesCache[i].put(MediaStore.Audio.Playlists.Members.AUDIO_ID, ids[offset + i]);
561f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen        }
562f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen    }
563792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
564bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public static void addToPlaylist(Context context, long [] ids, long playlistid) {
565792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (ids == null) {
566792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // this shouldn't happen (the menuitems shouldn't be visible
567792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // unless the selected item represents something playable
568792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Log.e("MusicBase", "ListSelection null");
569792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else {
570792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int size = ids.length;
571792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ContentResolver resolver = context.getContentResolver();
572792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // need to determine the number of items currently in the playlist,
573792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // so the play_order field can be maintained.
574792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String[] cols = new String[] {
575792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    "count(*)"
576792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            };
577792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistid);
578792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Cursor cur = resolver.query(uri, cols, null, null, null);
579792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            cur.moveToFirst();
580792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int base = cur.getInt(0);
581792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            cur.close();
582f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen            int numinserted = 0;
583f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen            for (int i = 0; i < size; i += 1000) {
584f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen                makeInsertItems(ids, i, 1000, base);
585f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen                numinserted += resolver.bulkInsert(uri, sContentValuesCache);
586792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
587792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String message = context.getResources().getQuantityString(
588f33a575c2b09095d58ad7af527113f767e4c37b1Marco Nelissen                    R.plurals.NNNtrackstoplaylist, numinserted, numinserted);
589792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
590792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //mLastPlaylistSelected = playlistid;
591792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
592792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
593792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
594792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static Cursor query(Context context, Uri uri, String[] projection,
5954248ed203f66145f8be7cda2cfd937ec450c9609Marco Nelissen            String selection, String[] selectionArgs, String sortOrder, int limit) {
596792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
597792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ContentResolver resolver = context.getContentResolver();
598792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (resolver == null) {
599792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return null;
600792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
6014248ed203f66145f8be7cda2cfd937ec450c9609Marco Nelissen            if (limit > 0) {
6024248ed203f66145f8be7cda2cfd937ec450c9609Marco Nelissen                uri = uri.buildUpon().appendQueryParameter("limit", "" + limit).build();
6034248ed203f66145f8be7cda2cfd937ec450c9609Marco Nelissen            }
604792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
605792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         } catch (UnsupportedOperationException ex) {
606792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return null;
607792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
608792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
609792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
6104248ed203f66145f8be7cda2cfd937ec450c9609Marco Nelissen    public static Cursor query(Context context, Uri uri, String[] projection,
6114248ed203f66145f8be7cda2cfd937ec450c9609Marco Nelissen            String selection, String[] selectionArgs, String sortOrder) {
6124248ed203f66145f8be7cda2cfd937ec450c9609Marco Nelissen        return query(context, uri, projection, selection, selectionArgs, sortOrder, 0);
6134248ed203f66145f8be7cda2cfd937ec450c9609Marco Nelissen    }
614792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
615792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static boolean isMediaScannerScanning(Context context) {
616792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        boolean result = false;
617792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Cursor cursor = query(context, MediaStore.getMediaScannerUri(),
618792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                new String [] { MediaStore.MEDIA_SCANNER_VOLUME }, null, null, null);
619792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (cursor != null) {
620792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (cursor.getCount() == 1) {
621792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                cursor.moveToFirst();
622792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                result = "external".equals(cursor.getString(0));
623792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
624792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            cursor.close();
625792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
626792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
627792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return result;
628792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
629792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
630792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static void setSpinnerState(Activity a) {
631792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (isMediaScannerScanning(a)) {
632792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // start the progress spinner
633792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            a.getWindow().setFeatureInt(
634792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    Window.FEATURE_INDETERMINATE_PROGRESS,
635792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    Window.PROGRESS_INDETERMINATE_ON);
636792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
637792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            a.getWindow().setFeatureInt(
638792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    Window.FEATURE_INDETERMINATE_PROGRESS,
639792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    Window.PROGRESS_VISIBILITY_ON);
640792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else {
641792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // stop the progress spinner
642792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            a.getWindow().setFeatureInt(
643792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    Window.FEATURE_INDETERMINATE_PROGRESS,
644792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    Window.PROGRESS_VISIBILITY_OFF);
645792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
646792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
647792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
6487a05298d5af6f796f3a260fa60b11d1c029b4207Marco Nelissen    private static String mLastSdStatus;
6497a05298d5af6f796f3a260fa60b11d1c029b4207Marco Nelissen
650792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static void displayDatabaseError(Activity a) {
65198b177710b6a9bb2de7498d68e10a0d7f53c2f06Marco Nelissen        if (a.isFinishing()) {
65298b177710b6a9bb2de7498d68e10a0d7f53c2f06Marco Nelissen            // When switching tabs really fast, we can end up with a null
65398b177710b6a9bb2de7498d68e10a0d7f53c2f06Marco Nelissen            // cursor (not sure why), which will bring us here.
65498b177710b6a9bb2de7498d68e10a0d7f53c2f06Marco Nelissen            // Don't bother showing an error message in that case.
65598b177710b6a9bb2de7498d68e10a0d7f53c2f06Marco Nelissen            return;
65698b177710b6a9bb2de7498d68e10a0d7f53c2f06Marco Nelissen        }
65798b177710b6a9bb2de7498d68e10a0d7f53c2f06Marco Nelissen
658792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        String status = Environment.getExternalStorageState();
659ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer        int title, message;
660ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer
661ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer        if (android.os.Environment.isExternalStorageRemovable()) {
662ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer            title = R.string.sdcard_error_title;
663ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer            message = R.string.sdcard_error_message;
664ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer        } else {
665ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer            title = R.string.sdcard_error_title_nosdcard;
666ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer            message = R.string.sdcard_error_message_nosdcard;
667ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer        }
668792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
669792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (status.equals(Environment.MEDIA_SHARED) ||
670792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                status.equals(Environment.MEDIA_UNMOUNTED)) {
671ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer            if (android.os.Environment.isExternalStorageRemovable()) {
672ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer                title = R.string.sdcard_busy_title;
673ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer                message = R.string.sdcard_busy_message;
674ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer            } else {
675ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer                title = R.string.sdcard_busy_title_nosdcard;
676ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer                message = R.string.sdcard_busy_message_nosdcard;
677ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer            }
678792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else if (status.equals(Environment.MEDIA_REMOVED)) {
679ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer            if (android.os.Environment.isExternalStorageRemovable()) {
680ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer                title = R.string.sdcard_missing_title;
681ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer                message = R.string.sdcard_missing_message;
682ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer            } else {
683ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer                title = R.string.sdcard_missing_title_nosdcard;
684ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer                message = R.string.sdcard_missing_message_nosdcard;
685ecf5b6577ed52056fa8ae6035805bfed9f50c2f3Eric Fischer            }
686792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else if (status.equals(Environment.MEDIA_MOUNTED)){
687792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // The card is mounted, but we didn't get a valid cursor.
688792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // This probably means the mediascanner hasn't started scanning the
689792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // card yet (there is a small window of time during boot where this
690792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // will happen).
691792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            a.setTitle("");
692792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Intent intent = new Intent();
693792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            intent.setClass(a, ScanningProgress.class);
694792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            a.startActivityForResult(intent, Defs.SCAN_DONE);
6957a05298d5af6f796f3a260fa60b11d1c029b4207Marco Nelissen        } else if (!TextUtils.equals(mLastSdStatus, status)) {
6967a05298d5af6f796f3a260fa60b11d1c029b4207Marco Nelissen            mLastSdStatus = status;
697792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Log.d(TAG, "sd card: " + status);
698792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
699792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
700792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        a.setTitle(title);
701792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        View v = a.findViewById(R.id.sd_message);
702792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (v != null) {
703792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            v.setVisibility(View.VISIBLE);
704792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
705792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        v = a.findViewById(R.id.sd_icon);
706792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (v != null) {
707792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            v.setVisibility(View.VISIBLE);
708792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
709792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        v = a.findViewById(android.R.id.list);
710792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (v != null) {
711792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            v.setVisibility(View.GONE);
712792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
7139e0f1fde0956ee7f5b76b77df7aea9b936e2c3a9Marco Nelissen        v = a.findViewById(R.id.buttonbar);
7149e0f1fde0956ee7f5b76b77df7aea9b936e2c3a9Marco Nelissen        if (v != null) {
7159e0f1fde0956ee7f5b76b77df7aea9b936e2c3a9Marco Nelissen            v.setVisibility(View.GONE);
7169e0f1fde0956ee7f5b76b77df7aea9b936e2c3a9Marco Nelissen        }
717792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        TextView tv = (TextView) a.findViewById(R.id.sd_message);
718792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        tv.setText(message);
719792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
720792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
721792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static void hideDatabaseError(Activity a) {
722792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        View v = a.findViewById(R.id.sd_message);
723792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (v != null) {
724792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            v.setVisibility(View.GONE);
725792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
726792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        v = a.findViewById(R.id.sd_icon);
727792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (v != null) {
728792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            v.setVisibility(View.GONE);
729792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
730792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        v = a.findViewById(android.R.id.list);
731792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (v != null) {
732792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            v.setVisibility(View.VISIBLE);
733792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
734792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
735792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
736792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    static protected Uri getContentURIForPath(String path) {
737792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return Uri.fromFile(new File(path));
738792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
739792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
740792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
741792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /*  Try to use String.format() as little as possible, because it creates a
742792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *  new Formatter every time you call it, which is very inefficient.
743792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *  Reusing an existing Formatter more than tripled the speed of
744792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *  makeTimeString().
745792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *  This Formatter/StringBuilder are also used by makeAlbumSongsLabel()
746792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
747792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static StringBuilder sFormatBuilder = new StringBuilder();
748792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static Formatter sFormatter = new Formatter(sFormatBuilder, Locale.getDefault());
749792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final Object[] sTimeArgs = new Object[5];
750792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
751792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static String makeTimeString(Context context, long secs) {
7521e5a567390e41045cba6abac1d2c94eb8f59fc30Marco Nelissen        String durationformat = context.getString(
7531e5a567390e41045cba6abac1d2c94eb8f59fc30Marco Nelissen                secs < 3600 ? R.string.durationformatshort : R.string.durationformatlong);
754792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
755792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        /* Provide multiple arguments so the format can be changed easily
756792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * by modifying the xml.
757792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         */
758792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        sFormatBuilder.setLength(0);
759792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
760792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        final Object[] timeArgs = sTimeArgs;
761792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        timeArgs[0] = secs / 3600;
762792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        timeArgs[1] = secs / 60;
763792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        timeArgs[2] = (secs / 60) % 60;
764792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        timeArgs[3] = secs;
765792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        timeArgs[4] = secs % 60;
766792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
767792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return sFormatter.format(durationformat, timeArgs).toString();
768792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
769792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
770792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static void shuffleAll(Context context, Cursor cursor) {
771792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        playAll(context, cursor, 0, true);
772792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
773792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
774792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static void playAll(Context context, Cursor cursor) {
775792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        playAll(context, cursor, 0, false);
776792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
777792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
778792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static void playAll(Context context, Cursor cursor, int position) {
779792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        playAll(context, cursor, position, false);
780792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
781792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
782bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public static void playAll(Context context, long [] list, int position) {
783792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        playAll(context, list, position, false);
784792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
785792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
786792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static void playAll(Context context, Cursor cursor, int position, boolean force_shuffle) {
787792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
788bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        long [] list = getSongListForCursor(cursor);
789792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        playAll(context, list, position, force_shuffle);
790792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
791792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
792bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    private static void playAll(Context context, long [] list, int position, boolean force_shuffle) {
793792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (list.length == 0 || sService == null) {
794792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Log.d("MusicUtils", "attempt to play empty song list");
795792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Don't try to play empty playlists. Nothing good will come of it.
796792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String message = context.getString(R.string.emptyplaylist, list.length);
797792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
798792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return;
799792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
800792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
801792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (force_shuffle) {
802792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                sService.setShuffleMode(MediaPlaybackService.SHUFFLE_NORMAL);
803792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
804bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long curid = sService.getAudioId();
805792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int curpos = sService.getQueuePosition();
806792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (position != -1 && curpos == position && curid == list[position]) {
807792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // The selected file is the file that's currently playing;
808792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // figure out if we need to restart with a new playlist,
809792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // or just launch the playback activity.
810bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                long [] playlist = sService.getQueue();
811792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (Arrays.equals(list, playlist)) {
812792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // we don't need to set a new list, but we should resume playback if needed
813792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    sService.play();
814792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return; // the 'finally' block will still run
815792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
816792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
817792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (position < 0) {
818792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                position = 0;
819792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
820792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            sService.open(list, force_shuffle ? -1 : position);
821792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            sService.play();
822792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } catch (RemoteException ex) {
823792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } finally {
82438bcd927f46d6477e6bae88795c38bfe92d7a9f9Marco Nelissen            Intent intent = new Intent("com.android.music.PLAYBACK_VIEWER")
825792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
826792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            context.startActivity(intent);
827792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
828792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
829792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
830792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static void clearQueue() {
831792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
832792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            sService.removeTracks(0, Integer.MAX_VALUE);
833792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } catch (RemoteException ex) {
834792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
835792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
836792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
837792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // A really simple BitmapDrawable-like class, that doesn't do
838792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // scaling, dithering or filtering.
839792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static class FastBitmapDrawable extends Drawable {
840792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private Bitmap mBitmap;
841792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public FastBitmapDrawable(Bitmap b) {
842792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mBitmap = b;
843792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
844792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
845792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void draw(Canvas canvas) {
846792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            canvas.drawBitmap(mBitmap, 0, 0, null);
847792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
848792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
849792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getOpacity() {
850792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return PixelFormat.OPAQUE;
851792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
852792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
853792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setAlpha(int alpha) {
854792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
855792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
856792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setColorFilter(ColorFilter cf) {
857792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
858792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
859792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
860792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static int sArtId = -2;
861792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static Bitmap mCachedBit = null;
862792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final BitmapFactory.Options sBitmapOptionsCache = new BitmapFactory.Options();
863792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final BitmapFactory.Options sBitmapOptions = new BitmapFactory.Options();
864792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
865bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    private static final HashMap<Long, Drawable> sArtCache = new HashMap<Long, Drawable>();
866792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static int sArtCacheId = -1;
867792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
868792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    static {
869792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // for the cache,
870792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // 565 is faster to decode and display
871792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // and we don't want to dither here because the image will be scaled down later
872792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        sBitmapOptionsCache.inPreferredConfig = Bitmap.Config.RGB_565;
873792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        sBitmapOptionsCache.inDither = false;
874792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
875792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        sBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;
876792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        sBitmapOptions.inDither = false;
877792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
878792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
879792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static void initAlbumArtCache() {
880792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
881792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int id = sService.getMediaMountedCount();
882792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (id != sArtCacheId) {
883792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                clearAlbumArtCache();
884792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                sArtCacheId = id;
885792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
886792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } catch (RemoteException e) {
887792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            e.printStackTrace();
888792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
889792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
890792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
891792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static void clearAlbumArtCache() {
892792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(sArtCache) {
893792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            sArtCache.clear();
894792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
895792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
896792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
897bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public static Drawable getCachedArtwork(Context context, long artIndex, BitmapDrawable defaultArtwork) {
898792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Drawable d = null;
899792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(sArtCache) {
900792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            d = sArtCache.get(artIndex);
901792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
902792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (d == null) {
903792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            d = defaultArtwork;
904792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            final Bitmap icon = defaultArtwork.getBitmap();
905792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int w = icon.getWidth();
906792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int h = icon.getHeight();
907792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Bitmap b = MusicUtils.getArtworkQuick(context, artIndex, w, h);
908792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (b != null) {
909792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                d = new FastBitmapDrawable(b);
910792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                synchronized(sArtCache) {
911792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // the cache may have changed since we checked
912792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    Drawable value = sArtCache.get(artIndex);
913792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (value == null) {
914792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        sArtCache.put(artIndex, d);
915792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
916792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        d = value;
917792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
918792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
919792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
920792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
921792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return d;
922792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
923792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
924792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // Get album art for specified album. This method will not try to
925792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // fall back to getting artwork directly from the file, nor will
926792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // it attempt to repair the database.
927bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    private static Bitmap getArtworkQuick(Context context, long album_id, int w, int h) {
928792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // NOTE: There is in fact a 1 pixel border on the right side in the ImageView
929792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // used to display this drawable. Take it into account now, so we don't have to
930792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // scale later.
931792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        w -= 1;
932792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ContentResolver res = context.getContentResolver();
933792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Uri uri = ContentUris.withAppendedId(sArtworkUri, album_id);
934792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (uri != null) {
935792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ParcelFileDescriptor fd = null;
936792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            try {
937792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                fd = res.openFileDescriptor(uri, "r");
938792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int sampleSize = 1;
939792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
940792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // Compute the closest power-of-two scale factor
941792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // and pass that to sBitmapOptionsCache.inSampleSize, which will
942792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // result in faster decoding and better quality
943792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                sBitmapOptionsCache.inJustDecodeBounds = true;
944792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                BitmapFactory.decodeFileDescriptor(
945792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        fd.getFileDescriptor(), null, sBitmapOptionsCache);
946792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int nextWidth = sBitmapOptionsCache.outWidth >> 1;
947792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int nextHeight = sBitmapOptionsCache.outHeight >> 1;
948792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                while (nextWidth>w && nextHeight>h) {
949792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    sampleSize <<= 1;
950792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    nextWidth >>= 1;
951792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    nextHeight >>= 1;
952792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
953792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
954792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                sBitmapOptionsCache.inSampleSize = sampleSize;
955792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                sBitmapOptionsCache.inJustDecodeBounds = false;
956792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Bitmap b = BitmapFactory.decodeFileDescriptor(
957792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        fd.getFileDescriptor(), null, sBitmapOptionsCache);
958792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
959792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (b != null) {
960792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // finally rescale to exactly the size we need
961792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (sBitmapOptionsCache.outWidth != w || sBitmapOptionsCache.outHeight != h) {
962792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        Bitmap tmp = Bitmap.createScaledBitmap(b, w, h, true);
963792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // Bitmap.createScaledBitmap() can return the same bitmap
964792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        if (tmp != b) b.recycle();
965792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        b = tmp;
966792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
967792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
968792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
969792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return b;
970792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (FileNotFoundException e) {
971792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } finally {
972792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                try {
973792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (fd != null)
974792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        fd.close();
975792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } catch (IOException e) {
976792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
977792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
978792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
979792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return null;
980792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
9813193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen
982792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Get album art for specified album. You should not pass in the album id
983792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * for the "unknown" album here (use -1 instead)
9843193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen     * This method always returns the default album art icon when no album art is found.
985792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
986bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public static Bitmap getArtwork(Context context, long song_id, long album_id) {
9873193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        return getArtwork(context, song_id, album_id, true);
9883193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen    }
9893193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen
9903193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen    /** Get album art for specified album. You should not pass in the album id
9913193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen     * for the "unknown" album here (use -1 instead)
9923193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen     */
9933193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen    public static Bitmap getArtwork(Context context, long song_id, long album_id,
9943193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen            boolean allowdefault) {
995792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
996792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (album_id < 0) {
997792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // This is something that is not in the database, so get the album art directly
998792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // from the file.
9997a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen            if (song_id >= 0) {
10007a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen                Bitmap bm = getArtworkFromFile(context, song_id, -1);
10017a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen                if (bm != null) {
10027a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen                    return bm;
10037a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen                }
1004792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
10053193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen            if (allowdefault) {
10063193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen                return getDefaultArtwork(context);
10073193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen            }
10083193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen            return null;
1009792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1010792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1011792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ContentResolver res = context.getContentResolver();
1012792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Uri uri = ContentUris.withAppendedId(sArtworkUri, album_id);
1013792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (uri != null) {
1014792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            InputStream in = null;
1015792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            try {
1016792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                in = res.openInputStream(uri);
1017792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return BitmapFactory.decodeStream(in, null, sBitmapOptions);
1018792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (FileNotFoundException ex) {
1019792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // The album art thumbnail does not actually exist. Maybe the user deleted it, or
1020792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // maybe it never existed to begin with.
10217a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen                Bitmap bm = getArtworkFromFile(context, song_id, album_id);
1022792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (bm != null) {
1023756c3f57f11a7bb3bf1cf1333ee8ffbc51039748Marco Nelissen                    if (bm.getConfig() == null) {
1024756c3f57f11a7bb3bf1cf1333ee8ffbc51039748Marco Nelissen                        bm = bm.copy(Bitmap.Config.RGB_565, false);
10253193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen                        if (bm == null && allowdefault) {
10267a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen                            return getDefaultArtwork(context);
1027792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        }
1028792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
10293193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen                } else if (allowdefault) {
10307a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen                    bm = getDefaultArtwork(context);
1031792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1032792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return bm;
1033792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } finally {
1034792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                try {
1035792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (in != null) {
1036792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        in.close();
1037792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1038792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } catch (IOException ex) {
1039792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1040792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1041792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1042792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1043792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return null;
1044792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1045792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1046792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // get album art for specified file
1047792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final String sExternalMediaUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.toString();
1048bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    private static Bitmap getArtworkFromFile(Context context, long songid, long albumid) {
1049792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Bitmap bm = null;
1050792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        byte [] art = null;
1051792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        String path = null;
1052792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
10537a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen        if (albumid < 0 && songid < 0) {
10547a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen            throw new IllegalArgumentException("Must specify an album or a song id");
1055792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
10567a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen
10577a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen        try {
10587a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen            if (albumid < 0) {
10597a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen                Uri uri = Uri.parse("content://media/external/audio/media/" + songid + "/albumart");
10607a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen                ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "r");
10617a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen                if (pfd != null) {
10627a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen                    FileDescriptor fd = pfd.getFileDescriptor();
10637a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen                    bm = BitmapFactory.decodeFileDescriptor(fd);
1064792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
10657a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen            } else {
10667a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen                Uri uri = ContentUris.withAppendedId(sArtworkUri, albumid);
10677a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen                ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "r");
10687a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen                if (pfd != null) {
10697a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen                    FileDescriptor fd = pfd.getFileDescriptor();
10707a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen                    bm = BitmapFactory.decodeFileDescriptor(fd);
1071792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1072792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1073dfc404c527e41c4bbc1804caba6ad5008309ec22Marco Nelissen        } catch (IllegalStateException ex) {
10747a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen        } catch (FileNotFoundException ex) {
1075792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
10767a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen        if (bm != null) {
10777a16cc726fd83eff0095f3f82364d1438773218fMarco Nelissen            mCachedBit = bm;
1078792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1079792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return bm;
1080792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1081792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1082792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static Bitmap getDefaultArtwork(Context context) {
1083792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        BitmapFactory.Options opts = new BitmapFactory.Options();
1084792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
1085792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return BitmapFactory.decodeStream(
1086792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                context.getResources().openRawResource(R.drawable.albumart_mp_unknown), null, opts);
1087792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1088792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1089792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    static int getIntPref(Context context, String name, int def) {
1090792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        SharedPreferences prefs =
109132b9f974fbbc0269e9293916dda265d0e18d0a29Marco Nelissen            context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
1092792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return prefs.getInt(name, def);
1093792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1094792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1095792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    static void setIntPref(Context context, String name, int value) {
1096792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        SharedPreferences prefs =
109732b9f974fbbc0269e9293916dda265d0e18d0a29Marco Nelissen            context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
1098792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Editor ed = prefs.edit();
1099792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.putInt(name, value);
110014c3caeb7bc2de0dd7abbb1e5f217dbb6367afbaBrad Fitzpatrick        SharedPreferencesCompat.apply(ed);
1101792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1102792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1103792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    static void setRingtone(Context context, long id) {
1104792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ContentResolver resolver = context.getContentResolver();
1105792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Set the flag in the database to mark this as a ringtone
1106792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Uri ringUri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id);
1107792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
1108792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ContentValues values = new ContentValues(2);
1109792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            values.put(MediaStore.Audio.Media.IS_RINGTONE, "1");
1110792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            values.put(MediaStore.Audio.Media.IS_ALARM, "1");
1111792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            resolver.update(ringUri, values, null, null);
1112792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } catch (UnsupportedOperationException ex) {
1113792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // most likely the card just got unmounted
1114792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Log.e(TAG, "couldn't set ringtone flag for id " + id);
1115792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return;
1116792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1117792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1118792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        String[] cols = new String[] {
1119792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                MediaStore.Audio.Media._ID,
1120792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                MediaStore.Audio.Media.DATA,
1121792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                MediaStore.Audio.Media.TITLE
1122792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        };
1123792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1124792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        String where = MediaStore.Audio.Media._ID + "=" + id;
1125792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Cursor cursor = query(context, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
1126792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                cols, where , null, null);
1127792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
1128792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (cursor != null && cursor.getCount() == 1) {
1129792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // Set the system setting to make this the current ringtone
1130792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                cursor.moveToFirst();
1131792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Settings.System.putString(resolver, Settings.System.RINGTONE, ringUri.toString());
1132792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String message = context.getString(R.string.ringtone_set, cursor.getString(2));
1133792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
1134792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1135792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } finally {
1136792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (cursor != null) {
1137792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                cursor.close();
1138792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1139792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1140792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1141ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen
1142ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen    static int sActiveTabIndex = -1;
1143ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen
114419cea9e16c54364a6a1df53cd617ba0a9c65b386Marco Nelissen    static boolean updateButtonBar(Activity a, int highlight) {
1145ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        final TabWidget ll = (TabWidget) a.findViewById(R.id.buttonbar);
1146ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        boolean withtabs = false;
1147ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        Intent intent = a.getIntent();
1148ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        if (intent != null) {
1149ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            withtabs = intent.getBooleanExtra("withtabs", false);
1150ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        }
1151ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen
1152ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        if (highlight == 0 || !withtabs) {
1153ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            ll.setVisibility(View.GONE);
115419cea9e16c54364a6a1df53cd617ba0a9c65b386Marco Nelissen            return withtabs;
1155ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        } else if (withtabs) {
1156ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            ll.setVisibility(View.VISIBLE);
1157ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        }
1158ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        for (int i = ll.getChildCount() - 1; i >= 0; i--) {
1159ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen
1160ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            View v = ll.getChildAt(i);
1161ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            boolean isActive = (v.getId() == highlight);
1162ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            if (isActive) {
1163ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                ll.setCurrentTab(i);
1164ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                sActiveTabIndex = i;
1165ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            }
1166333bf1945f859968dcb9783b694aa64b788fc771Jeff Hamilton            v.setTag(i);
1167ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            v.setOnFocusChangeListener(new View.OnFocusChangeListener() {
1168ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen
1169ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                public void onFocusChange(View v, boolean hasFocus) {
1170ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                    if (hasFocus) {
1171ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                        for (int i = 0; i < ll.getTabCount(); i++) {
1172ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                            if (ll.getChildTabViewAt(i) == v) {
1173ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                                ll.setCurrentTab(i);
1174ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                                processTabClick((Activity)ll.getContext(), v, ll.getChildAt(sActiveTabIndex).getId());
1175ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                                break;
1176ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                            }
1177ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                        }
1178ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                    }
1179ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                }});
1180ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen
1181ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            v.setOnClickListener(new View.OnClickListener() {
1182ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen
1183ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                public void onClick(View v) {
1184ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                    processTabClick((Activity)ll.getContext(), v, ll.getChildAt(sActiveTabIndex).getId());
1185ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                }});
1186ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        }
118719cea9e16c54364a6a1df53cd617ba0a9c65b386Marco Nelissen        return withtabs;
1188ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen    }
1189ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen
1190ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen    static void processTabClick(Activity a, View v, int current) {
1191ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        int id = v.getId();
1192ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        if (id == current) {
1193ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            return;
1194ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        }
1195333bf1945f859968dcb9783b694aa64b788fc771Jeff Hamilton
1196333bf1945f859968dcb9783b694aa64b788fc771Jeff Hamilton        final TabWidget ll = (TabWidget) a.findViewById(R.id.buttonbar);
1197333bf1945f859968dcb9783b694aa64b788fc771Jeff Hamilton
1198ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        activateTab(a, id);
1199ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        if (id != R.id.nowplayingtab) {
120038bcd927f46d6477e6bae88795c38bfe92d7a9f9Marco Nelissen            ll.setCurrentTab((Integer) v.getTag());
1201ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            setIntPref(a, "activetab", id);
1202ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        }
1203ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen    }
1204ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen
1205ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen    static void activateTab(Activity a, int id) {
1206ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        Intent intent = new Intent(Intent.ACTION_PICK);
1207ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        switch (id) {
1208ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            case R.id.artisttab:
1209ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/artistalbum");
1210ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                break;
1211ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            case R.id.albumtab:
1212ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/album");
1213ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                break;
1214ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            case R.id.songtab:
1215ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track");
1216ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                break;
1217ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            case R.id.playlisttab:
1218ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                intent.setDataAndType(Uri.EMPTY, MediaStore.Audio.Playlists.CONTENT_TYPE);
1219ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                break;
1220ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            case R.id.nowplayingtab:
1221ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                intent = new Intent(a, MediaPlaybackActivity.class);
1222ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                a.startActivity(intent);
1223ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                // fall through and return
1224ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            default:
1225ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                return;
1226ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        }
1227ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        intent.putExtra("withtabs", true);
1228ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1229ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        a.startActivity(intent);
1230ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        a.finish();
1231ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        a.overridePendingTransition(0, 0);
1232ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen    }
1233ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen
1234ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen    static void updateNowPlaying(Activity a) {
1235ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        View nowPlayingView = a.findViewById(R.id.nowplaying);
1236ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        if (nowPlayingView == null) {
1237ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            return;
1238ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        }
1239ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        try {
1240ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            boolean withtabs = false;
1241ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            Intent intent = a.getIntent();
1242ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            if (intent != null) {
1243ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                withtabs = intent.getBooleanExtra("withtabs", false);
1244ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            }
1245ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            if (true && MusicUtils.sService != null && MusicUtils.sService.getAudioId() != -1) {
1246ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                TextView title = (TextView) nowPlayingView.findViewById(R.id.title);
1247ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                TextView artist = (TextView) nowPlayingView.findViewById(R.id.artist);
1248ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                title.setText(MusicUtils.sService.getTrackName());
1249ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                String artistName = MusicUtils.sService.getArtistName();
1250f4d4b342061ade12eb7903f454df62814179906fMarco Nelissen                if (MediaStore.UNKNOWN_STRING.equals(artistName)) {
1251ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                    artistName = a.getString(R.string.unknown_artist_name);
1252ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                }
1253ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                artist.setText(artistName);
1254ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                //mNowPlayingView.setOnFocusChangeListener(mFocuser);
1255ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                //mNowPlayingView.setOnClickListener(this);
1256ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                nowPlayingView.setVisibility(View.VISIBLE);
1257ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                nowPlayingView.setOnClickListener(new View.OnClickListener() {
1258ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen
1259ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                    public void onClick(View v) {
1260ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                        Context c = v.getContext();
1261ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                        c.startActivity(new Intent(c, MediaPlaybackActivity.class));
1262ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                    }});
1263ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                return;
1264ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            }
1265ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        } catch (RemoteException ex) {
1266ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        }
1267ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen        nowPlayingView.setVisibility(View.GONE);
1268ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen    }
1269ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen
12703193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen    static void setBackground(View v, Bitmap bm) {
12713193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen
12723193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        if (bm == null) {
12733193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen            v.setBackgroundResource(0);
12743193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen            return;
12753193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        }
12763193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen
12773193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        int vwidth = v.getWidth();
12783193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        int vheight = v.getHeight();
12793193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        int bwidth = bm.getWidth();
12803193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        int bheight = bm.getHeight();
12813193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        float scalex = (float) vwidth / bwidth;
12823193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        float scaley = (float) vheight / bheight;
12833193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        float scale = Math.max(scalex, scaley) * 1.3f;
12843193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen
12853193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        Bitmap.Config config = Bitmap.Config.ARGB_8888;
12863193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        Bitmap bg = Bitmap.createBitmap(vwidth, vheight, config);
12873193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        Canvas c = new Canvas(bg);
12883193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        Paint paint = new Paint();
12893193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        paint.setAntiAlias(true);
12903193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        paint.setFilterBitmap(true);
12913193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        ColorMatrix greymatrix = new ColorMatrix();
12923193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        greymatrix.setSaturation(0);
12933193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        ColorMatrix darkmatrix = new ColorMatrix();
12943193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        darkmatrix.setScale(.3f, .3f, .3f, 1.0f);
12953193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        greymatrix.postConcat(darkmatrix);
12963193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        ColorFilter filter = new ColorMatrixColorFilter(greymatrix);
12973193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        paint.setColorFilter(filter);
12983193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        Matrix matrix = new Matrix();
12993193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        matrix.setTranslate(-bwidth/2, -bheight/2); // move bitmap center to origin
13003193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        matrix.postRotate(10);
13013193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        matrix.postScale(scale, scale);
13023193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        matrix.postTranslate(vwidth/2, vheight/2);  // Move bitmap center to view center
13033193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        c.drawBitmap(bm, matrix, paint);
13043193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen        v.setBackgroundDrawable(new BitmapDrawable(bg));
13053193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen    }
13063193d7dda28d5c31b318b024db4df40b949071d5Marco Nelissen
130787bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen    static int getCardId(Context context) {
130887bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen        ContentResolver res = context.getContentResolver();
130987bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen        Cursor c = res.query(Uri.parse("content://media/external/fs_id"), null, null, null, null);
131087bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen        int id = -1;
131187bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen        if (c != null) {
131287bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen            c.moveToFirst();
131387bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen            id = c.getInt(0);
131487bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen            c.close();
131587bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen        }
131687bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen        return id;
131787bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen    }
13183988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen
13193988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen    static class LogEntry {
13203988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        Object item;
13213988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        long time;
13223988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen
13233988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        LogEntry(Object o) {
13243988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            item = o;
13253988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            time = System.currentTimeMillis();
13263988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        }
13273988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen
13283988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        void dump(PrintWriter out) {
13293988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            sTime.set(time);
13303988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            out.print(sTime.toString() + " : ");
13313988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            if (item instanceof Exception) {
13323988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen                ((Exception)item).printStackTrace(out);
13333988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            } else {
13343988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen                out.println(item);
13353988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            }
13363988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        }
13373988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen    }
13383988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen
13393988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen    private static LogEntry[] sMusicLog = new LogEntry[100];
13403988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen    private static int sLogPtr = 0;
13413988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen    private static Time sTime = new Time();
13423988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen
13433988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen    static void debugLog(Object o) {
13443988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen
13453988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        sMusicLog[sLogPtr] = new LogEntry(o);
13463988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        sLogPtr++;
13473988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        if (sLogPtr >= sMusicLog.length) {
13483988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            sLogPtr = 0;
13493988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        }
13503988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen    }
13513988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen
13523988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen    static void debugDump(PrintWriter out) {
13533988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        for (int i = 0; i < sMusicLog.length; i++) {
13543988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            int idx = (sLogPtr + i);
13553988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            if (idx >= sMusicLog.length) {
13563988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen                idx -= sMusicLog.length;
13573988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            }
13583988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            LogEntry entry = sMusicLog[idx];
13593988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            if (entry != null) {
13603988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen                entry.dump(out);
13613988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            }
13623988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        }
13633988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen    }
1364792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project}
1365