Home | History | Annotate | Download | only in music
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.music;
     18 
     19 import android.app.Activity;
     20 import android.content.ContentResolver;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.content.SharedPreferences;
     24 import android.content.SharedPreferences.Editor;
     25 import android.content.res.Resources;
     26 import android.database.Cursor;
     27 import android.graphics.Bitmap;
     28 import android.graphics.Canvas;
     29 import android.graphics.ColorFilter;
     30 import android.graphics.PixelFormat;
     31 import android.graphics.drawable.BitmapDrawable;
     32 import android.graphics.drawable.Drawable;
     33 import android.media.MediaMetadata;
     34 import android.media.session.MediaController;
     35 import android.net.Uri;
     36 import android.provider.MediaStore;
     37 import android.view.View;
     38 import android.widget.TabWidget;
     39 import android.widget.TextView;
     40 import com.android.music.utils.LogHelper;
     41 import com.android.music.utils.MusicProvider;
     42 
     43 import java.util.Formatter;
     44 import java.util.Iterator;
     45 import java.util.Locale;
     46 
     47 /*
     48 Static methods useful for activities
     49  */
     50 public class MusicUtils {
     51     private static final String TAG = LogHelper.makeLogTag(MusicUtils.class);
     52 
     53     public static final String TAG_MEDIA_ID = "__MEDIA_ID";
     54     public static final String TAG_PARENT_ITEM = "__PARENT_ITEM";
     55     public static final String TAG_WITH_TABS = "__WITH_TABS";
     56 
     57     // A really simple BitmapDrawable-like class, that doesn't do
     58     // scaling, dithering or filtering.
     59     private static class FastBitmapDrawable extends Drawable {
     60         private Bitmap mBitmap;
     61         public FastBitmapDrawable(Bitmap b) {
     62             mBitmap = b;
     63         }
     64         @Override
     65         public void draw(Canvas canvas) {
     66             canvas.drawBitmap(mBitmap, 0, 0, null);
     67         }
     68         @Override
     69         public int getOpacity() {
     70             return PixelFormat.OPAQUE;
     71         }
     72         @Override
     73         public void setAlpha(int alpha) {}
     74         @Override
     75         public void setColorFilter(ColorFilter cf) {}
     76     }
     77 
     78     public static Bitmap resizeBitmap(Bitmap bitmap, Bitmap ref) {
     79         int w = ref.getWidth();
     80         int h = ref.getHeight();
     81         return Bitmap.createScaledBitmap(bitmap, w, h, false);
     82     }
     83 
     84     public static Drawable getDrawableBitmap(Bitmap bitmap, BitmapDrawable defaultArtwork) {
     85         final Bitmap icon = defaultArtwork.getBitmap();
     86         int w = icon.getWidth();
     87         int h = icon.getHeight();
     88         bitmap = Bitmap.createScaledBitmap(bitmap, w, h, false);
     89         return new FastBitmapDrawable(bitmap);
     90     }
     91 
     92     public static String makeAlbumsLabel(
     93             Context context, int numalbums, int numsongs, boolean isUnknown) {
     94         // There are two formats for the albums/songs information:
     95         // "N Song(s)"  - used for unknown artist/album
     96         // "N Album(s)" - used for known albums
     97 
     98         StringBuilder songs_albums = new StringBuilder();
     99 
    100         Resources r = context.getResources();
    101         if (isUnknown) {
    102             if (numsongs == 1) {
    103                 songs_albums.append(context.getString(R.string.onesong));
    104             } else {
    105                 String f = r.getQuantityText(R.plurals.Nsongs, numsongs).toString();
    106                 sFormatBuilder.setLength(0);
    107                 sFormatter.format(f, Integer.valueOf(numsongs));
    108                 songs_albums.append(sFormatBuilder);
    109             }
    110         } else {
    111             String f = r.getQuantityText(R.plurals.Nalbums, numalbums).toString();
    112             sFormatBuilder.setLength(0);
    113             sFormatter.format(f, Integer.valueOf(numalbums));
    114             songs_albums.append(sFormatBuilder);
    115             songs_albums.append(context.getString(R.string.albumsongseparator));
    116         }
    117         return songs_albums.toString();
    118     }
    119 
    120     /**
    121      * This is now only used for the query screen
    122      */
    123     public static String makeAlbumsSongsLabel(
    124             Context context, int numalbums, int numsongs, boolean isUnknown) {
    125         // There are several formats for the albums/songs information:
    126         // "1 Song"   - used if there is only 1 song
    127         // "N Songs" - used for the "unknown artist" item
    128         // "1 Album"/"N Songs"
    129         // "N Album"/"M Songs"
    130         // Depending on locale, these may need to be further subdivided
    131 
    132         StringBuilder songs_albums = new StringBuilder();
    133 
    134         if (numsongs == 1) {
    135             songs_albums.append(context.getString(R.string.onesong));
    136         } else {
    137             Resources r = context.getResources();
    138             if (!isUnknown) {
    139                 String f = r.getQuantityText(R.plurals.Nalbums, numalbums).toString();
    140                 sFormatBuilder.setLength(0);
    141                 sFormatter.format(f, Integer.valueOf(numalbums));
    142                 songs_albums.append(sFormatBuilder);
    143                 songs_albums.append(context.getString(R.string.albumsongseparator));
    144             }
    145             String f = r.getQuantityText(R.plurals.Nsongs, numsongs).toString();
    146             sFormatBuilder.setLength(0);
    147             sFormatter.format(f, Integer.valueOf(numsongs));
    148             songs_albums.append(sFormatBuilder);
    149         }
    150         return songs_albums.toString();
    151     }
    152 
    153     /*  Try to use String.format() as little as possible, because it creates a
    154      *  new Formatter every time you call it, which is very inefficient.
    155      *  Reusing an existing Formatter more than tripled the speed of
    156      *  makeTimeString().
    157      *  This Formatter/StringBuilder are also used by makeAlbumSongsLabel()
    158      */
    159     private static StringBuilder sFormatBuilder = new StringBuilder();
    160     private static Formatter sFormatter = new Formatter(sFormatBuilder, Locale.getDefault());
    161     private static final Object[] sTimeArgs = new Object[5];
    162 
    163     public static String makeTimeString(Context context, long secs) {
    164         String durationformat = context.getString(
    165                 secs < 3600 ? R.string.durationformatshort : R.string.durationformatlong);
    166 
    167         /* Provide multiple arguments so the format can be changed easily
    168          * by modifying the xml.
    169          */
    170         sFormatBuilder.setLength(0);
    171 
    172         final Object[] timeArgs = sTimeArgs;
    173         timeArgs[0] = secs / 3600;
    174         timeArgs[1] = secs / 60;
    175         timeArgs[2] = (secs / 60) % 60;
    176         timeArgs[3] = secs;
    177         timeArgs[4] = secs % 60;
    178 
    179         return sFormatter.format(durationformat, timeArgs).toString();
    180     }
    181 
    182     static int getIntPref(Context context, String name, int def) {
    183         SharedPreferences prefs =
    184                 context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
    185         return prefs.getInt(name, def);
    186     }
    187 
    188     static void setIntPref(Context context, String name, int value) {
    189         SharedPreferences prefs =
    190                 context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
    191         Editor ed = prefs.edit();
    192         ed.putInt(name, value);
    193         SharedPreferencesCompat.apply(ed);
    194     }
    195 
    196     static int sActiveTabIndex = -1;
    197 
    198     static boolean updateButtonBar(Activity a, int highlight) {
    199         final TabWidget ll = (TabWidget) a.findViewById(R.id.buttonbar);
    200         boolean withtabs = false;
    201         Intent intent = a.getIntent();
    202         if (intent != null) {
    203             withtabs = intent.getBooleanExtra(MusicUtils.TAG_WITH_TABS, false);
    204         }
    205 
    206         if (highlight == 0 || !withtabs) {
    207             ll.setVisibility(View.GONE);
    208             return withtabs;
    209         } else if (withtabs) {
    210             ll.setVisibility(View.VISIBLE);
    211         }
    212         for (int i = ll.getChildCount() - 1; i >= 0; i--) {
    213             View v = ll.getChildAt(i);
    214             boolean isActive = (v.getId() == highlight);
    215             if (isActive) {
    216                 ll.setCurrentTab(i);
    217                 sActiveTabIndex = i;
    218             }
    219             v.setTag(i);
    220             v.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    221 
    222                 public void onFocusChange(View v, boolean hasFocus) {
    223                     if (hasFocus) {
    224                         for (int i = 0; i < ll.getTabCount(); i++) {
    225                             if (ll.getChildTabViewAt(i) == v) {
    226                                 ll.setCurrentTab(i);
    227                                 processTabClick((Activity) ll.getContext(), v,
    228                                         ll.getChildAt(sActiveTabIndex).getId());
    229                                 break;
    230                             }
    231                         }
    232                     }
    233                 }
    234             });
    235 
    236             v.setOnClickListener(new View.OnClickListener() {
    237 
    238                 public void onClick(View v) {
    239                     processTabClick(
    240                             (Activity) ll.getContext(), v, ll.getChildAt(sActiveTabIndex).getId());
    241                 }
    242             });
    243         }
    244         return withtabs;
    245     }
    246 
    247     static void processTabClick(Activity a, View v, int current) {
    248         int id = v.getId();
    249         if (id == current) {
    250             return;
    251         }
    252 
    253         final TabWidget ll = (TabWidget) a.findViewById(R.id.buttonbar);
    254 
    255         activateTab(a, id);
    256         if (id != R.id.nowplayingtab) {
    257             ll.setCurrentTab((Integer) v.getTag());
    258             setIntPref(a, "activetab", id);
    259         }
    260     }
    261 
    262     static void activateTab(Activity a, int id) {
    263         Intent intent = new Intent(Intent.ACTION_PICK);
    264         switch (id) {
    265             case R.id.artisttab:
    266                 intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/artistalbum");
    267                 break;
    268             case R.id.albumtab:
    269                 intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/album");
    270                 break;
    271             case R.id.songtab:
    272                 intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track");
    273                 break;
    274             case R.id.playlisttab:
    275                 intent.setDataAndType(Uri.EMPTY, MediaStore.Audio.Playlists.CONTENT_TYPE);
    276                 break;
    277             case R.id.nowplayingtab:
    278                 intent = new Intent(a, MediaPlaybackActivity.class);
    279                 a.startActivity(intent);
    280             // fall through and return
    281             default:
    282                 return;
    283         }
    284         intent.putExtra(MusicUtils.TAG_WITH_TABS, true);
    285         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    286         a.startActivity(intent);
    287         a.finish();
    288         a.overridePendingTransition(0, 0);
    289     }
    290 
    291     static void updateNowPlaying(Activity a) {
    292         View nowPlayingView = a.findViewById(R.id.nowplaying);
    293         if (nowPlayingView == null) {
    294             return;
    295         }
    296         MediaController controller = a.getMediaController();
    297         if (controller != null) {
    298             MediaMetadata metadata = controller.getMetadata();
    299             if (metadata != null) {
    300                 TextView title = (TextView) nowPlayingView.findViewById(R.id.title);
    301                 TextView artist = (TextView) nowPlayingView.findViewById(R.id.artist);
    302                 title.setText(metadata.getString(MediaMetadata.METADATA_KEY_TITLE));
    303                 String artistName = metadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
    304                 if (MusicProvider.UNKOWN.equals(artistName)) {
    305                     artistName = a.getString(R.string.unknown_artist_name);
    306                 }
    307                 artist.setText(artistName);
    308                 nowPlayingView.setVisibility(View.VISIBLE);
    309                 nowPlayingView.setOnClickListener(new View.OnClickListener() {
    310                     public void onClick(View v) {
    311                         Context c = v.getContext();
    312                         c.startActivity(new Intent(c, MediaPlaybackActivity.class));
    313                     }
    314                 });
    315                 return;
    316             }
    317         }
    318         nowPlayingView.setVisibility(View.GONE);
    319     }
    320 }
    321