Home | History | Annotate | Download | only in media
      1 /*
      2  * Copyright 2018 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 androidx.media;
     18 
     19 import static androidx.media.MediaMetadata2.METADATA_KEY_DISPLAY_DESCRIPTION;
     20 import static androidx.media.MediaMetadata2.METADATA_KEY_DISPLAY_ICON;
     21 import static androidx.media.MediaMetadata2.METADATA_KEY_DISPLAY_ICON_URI;
     22 import static androidx.media.MediaMetadata2.METADATA_KEY_DISPLAY_SUBTITLE;
     23 import static androidx.media.MediaMetadata2.METADATA_KEY_DISPLAY_TITLE;
     24 import static androidx.media.MediaMetadata2.METADATA_KEY_EXTRAS;
     25 import static androidx.media.MediaMetadata2.METADATA_KEY_MEDIA_ID;
     26 import static androidx.media.MediaMetadata2.METADATA_KEY_MEDIA_URI;
     27 import static androidx.media.MediaMetadata2.METADATA_KEY_TITLE;
     28 
     29 import android.graphics.Bitmap;
     30 import android.net.Uri;
     31 import android.os.Bundle;
     32 import android.os.Parcelable;
     33 import android.support.v4.media.MediaBrowserCompat.MediaItem;
     34 import android.support.v4.media.MediaDescriptionCompat;
     35 import android.support.v4.media.MediaMetadataCompat;
     36 import android.support.v4.media.RatingCompat;
     37 import android.support.v4.media.session.PlaybackStateCompat;
     38 
     39 import androidx.media.MediaSession2.CommandButton;
     40 
     41 import java.util.ArrayList;
     42 import java.util.List;
     43 
     44 class MediaUtils2 {
     45     static final String TAG = "MediaUtils2";
     46 
     47     private MediaUtils2() {
     48     }
     49 
     50     /**
     51      * Creates a {@link MediaItem} from the {@link MediaItem2}.
     52      *
     53      * @param item2 an item.
     54      * @return The newly created media item.
     55      */
     56     static MediaItem createMediaItem(MediaItem2 item2) {
     57         if (item2 == null) {
     58             return null;
     59         }
     60         MediaDescriptionCompat descCompat;
     61 
     62         MediaMetadata2 metadata = item2.getMetadata();
     63         if (metadata == null) {
     64             descCompat = new MediaDescriptionCompat.Builder()
     65                     .setMediaId(item2.getMediaId())
     66                     .build();
     67         } else {
     68             MediaDescriptionCompat.Builder builder = new MediaDescriptionCompat.Builder()
     69                     .setMediaId(item2.getMediaId())
     70                     .setSubtitle(metadata.getText(METADATA_KEY_DISPLAY_SUBTITLE))
     71                     .setDescription(metadata.getText(METADATA_KEY_DISPLAY_DESCRIPTION))
     72                     .setIconBitmap(metadata.getBitmap(METADATA_KEY_DISPLAY_ICON))
     73                     .setExtras(metadata.getExtras());
     74 
     75             String title = metadata.getString(METADATA_KEY_TITLE);
     76             if (title != null) {
     77                 builder.setTitle(title);
     78             } else {
     79                 builder.setTitle(metadata.getString(METADATA_KEY_DISPLAY_TITLE));
     80             }
     81 
     82             String displayIconUri = metadata.getString(METADATA_KEY_DISPLAY_ICON_URI);
     83             if (displayIconUri != null) {
     84                 builder.setIconUri(Uri.parse(displayIconUri));
     85             }
     86 
     87             String mediaUri = metadata.getString(METADATA_KEY_MEDIA_URI);
     88             if (mediaUri != null) {
     89                 builder.setMediaUri(Uri.parse(mediaUri));
     90             }
     91 
     92             descCompat = builder.build();
     93         }
     94         return new MediaItem(descCompat, item2.getFlags());
     95     }
     96 
     97     /**
     98      * Creates a {@link MediaItem2} from the {@link MediaItem}.
     99      *
    100      * @param item an item.
    101      * @return The newly created media item.
    102      */
    103     static MediaItem2 createMediaItem2(MediaItem item) {
    104         if (item == null || item.getMediaId() == null) {
    105             return null;
    106         }
    107 
    108         MediaMetadata2 metadata2 = createMediaMetadata2(item.getDescription());
    109         return new MediaItem2.Builder(item.getFlags())
    110                 .setMediaId(item.getMediaId())
    111                 .setMetadata(metadata2)
    112                 .build();
    113     }
    114 
    115     static List<MediaItem> fromMediaItem2List(List<MediaItem2> items) {
    116         if (items == null) {
    117             return null;
    118         }
    119         List<MediaItem> result = new ArrayList<>();
    120         for (int i = 0; i < items.size(); i++) {
    121             result.add(createMediaItem(items.get(i)));
    122         }
    123         return result;
    124     }
    125 
    126     static List<MediaItem2> toMediaItem2List(List<MediaItem> items) {
    127         if (items == null) {
    128             return null;
    129         }
    130         List<MediaItem2> result = new ArrayList<>();
    131         for (int i = 0; i < items.size(); i++) {
    132             result.add(createMediaItem2(items.get(i)));
    133         }
    134         return result;
    135     }
    136 
    137     /**
    138      * Creates a {@link MediaMetadata2} from the {@link MediaDescriptionCompat}.
    139      *
    140      * @param descCompat A {@link MediaDescriptionCompat} object.
    141      * @return The newly created {@link MediaMetadata2} object.
    142      */
    143     static MediaMetadata2 createMediaMetadata2(MediaDescriptionCompat descCompat) {
    144         if (descCompat == null) {
    145             return null;
    146         }
    147 
    148         MediaMetadata2.Builder metadata2Builder = new MediaMetadata2.Builder();
    149         metadata2Builder.putString(METADATA_KEY_MEDIA_ID, descCompat.getMediaId());
    150 
    151         CharSequence title = descCompat.getTitle();
    152         if (title != null) {
    153             metadata2Builder.putText(METADATA_KEY_DISPLAY_TITLE, title);
    154         }
    155 
    156         CharSequence description = descCompat.getDescription();
    157         if (description != null) {
    158             metadata2Builder.putText(METADATA_KEY_DISPLAY_DESCRIPTION, descCompat.getDescription());
    159         }
    160 
    161         CharSequence subtitle = descCompat.getSubtitle();
    162         if (subtitle != null) {
    163             metadata2Builder.putText(METADATA_KEY_DISPLAY_SUBTITLE, subtitle);
    164         }
    165 
    166         Bitmap icon = descCompat.getIconBitmap();
    167         if (icon != null) {
    168             metadata2Builder.putBitmap(METADATA_KEY_DISPLAY_ICON, icon);
    169         }
    170 
    171         Uri iconUri = descCompat.getIconUri();
    172         if (iconUri != null) {
    173             metadata2Builder.putText(METADATA_KEY_DISPLAY_ICON_URI, iconUri.toString());
    174         }
    175 
    176         Bundle bundle = descCompat.getExtras();
    177         if (bundle != null) {
    178             metadata2Builder.setExtras(descCompat.getExtras());
    179         }
    180 
    181         Uri mediaUri = descCompat.getMediaUri();
    182         if (mediaUri != null) {
    183             metadata2Builder.putText(METADATA_KEY_MEDIA_URI, mediaUri.toString());
    184         }
    185 
    186         return metadata2Builder.build();
    187     }
    188 
    189     /**
    190      * Creates a {@link MediaMetadata2} from the {@link MediaMetadataCompat}.
    191      *
    192      * @param metadataCompat A {@link MediaMetadataCompat} object.
    193      * @return The newly created {@link MediaMetadata2} object.
    194      */
    195     MediaMetadata2 createMediaMetadata2(MediaMetadataCompat metadataCompat) {
    196         if (metadataCompat == null) {
    197             return null;
    198         }
    199         return new MediaMetadata2(metadataCompat.getBundle());
    200     }
    201 
    202     /**
    203      * Creates a {@link MediaMetadataCompat} from the {@link MediaMetadata2}.
    204      *
    205      * @param metadata2 A {@link MediaMetadata2} object.
    206      * @return The newly created {@link MediaMetadataCompat} object.
    207      */
    208     MediaMetadataCompat createMediaMetadataCompat(MediaMetadata2 metadata2) {
    209         if (metadata2 == null) {
    210             return null;
    211         }
    212 
    213         MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
    214 
    215         List<String> skippedKeys = new ArrayList<>();
    216         Bundle bundle = metadata2.toBundle();
    217         for (String key : bundle.keySet()) {
    218             Object value = bundle.get(key);
    219             if (value instanceof CharSequence) {
    220                 builder.putText(key, (CharSequence) value);
    221             } else if (value instanceof Rating2) {
    222                 builder.putRating(key, createRatingCompat((Rating2) value));
    223             } else if (value instanceof Bitmap) {
    224                 builder.putBitmap(key, (Bitmap) value);
    225             } else if (value instanceof Long) {
    226                 builder.putLong(key, (Long) value);
    227             } else {
    228                 // There is no 'float' or 'bundle' type in MediaMetadataCompat.
    229                 skippedKeys.add(key);
    230             }
    231         }
    232 
    233         MediaMetadataCompat result = builder.build();
    234         for (String key : skippedKeys) {
    235             Object value = bundle.get(key);
    236             if (value instanceof Float) {
    237                 // Compatibility for MediaMetadata2.Builder.putFloat()
    238                 result.getBundle().putFloat(key, (Float) value);
    239             } else if (METADATA_KEY_EXTRAS.equals(value)) {
    240                 // Compatibility for MediaMetadata2.Builder.setExtras()
    241                 result.getBundle().putBundle(key, (Bundle) value);
    242             }
    243         }
    244         return result;
    245     }
    246 
    247     /**
    248      * Creates a {@link Rating2} from the {@link RatingCompat}.
    249      *
    250      * @param ratingCompat A {@link RatingCompat} object.
    251      * @return The newly created {@link Rating2} object.
    252      */
    253     Rating2 createRating2(RatingCompat ratingCompat) {
    254         if (ratingCompat == null) {
    255             return null;
    256         }
    257         if (!ratingCompat.isRated()) {
    258             return Rating2.newUnratedRating(ratingCompat.getRatingStyle());
    259         }
    260 
    261         switch (ratingCompat.getRatingStyle()) {
    262             case RatingCompat.RATING_3_STARS:
    263             case RatingCompat.RATING_4_STARS:
    264             case RatingCompat.RATING_5_STARS:
    265                 return Rating2.newStarRating(
    266                         ratingCompat.getRatingStyle(), ratingCompat.getStarRating());
    267             case RatingCompat.RATING_HEART:
    268                 return Rating2.newHeartRating(ratingCompat.hasHeart());
    269             case RatingCompat.RATING_THUMB_UP_DOWN:
    270                 return Rating2.newThumbRating(ratingCompat.isThumbUp());
    271             case RatingCompat.RATING_PERCENTAGE:
    272                 return Rating2.newPercentageRating(ratingCompat.getPercentRating());
    273             default:
    274                 return null;
    275         }
    276     }
    277 
    278     /**
    279      * Creates a {@link RatingCompat} from the {@link Rating2}.
    280      *
    281      * @param rating2 A {@link Rating2} object.
    282      * @return The newly created {@link RatingCompat} object.
    283      */
    284     RatingCompat createRatingCompat(Rating2 rating2) {
    285         if (rating2 == null) {
    286             return null;
    287         }
    288         if (!rating2.isRated()) {
    289             return RatingCompat.newUnratedRating(rating2.getRatingStyle());
    290         }
    291 
    292         switch (rating2.getRatingStyle()) {
    293             case Rating2.RATING_3_STARS:
    294             case Rating2.RATING_4_STARS:
    295             case Rating2.RATING_5_STARS:
    296                 return RatingCompat.newStarRating(
    297                         rating2.getRatingStyle(), rating2.getStarRating());
    298             case Rating2.RATING_HEART:
    299                 return RatingCompat.newHeartRating(rating2.hasHeart());
    300             case Rating2.RATING_THUMB_UP_DOWN:
    301                 return RatingCompat.newThumbRating(rating2.isThumbUp());
    302             case Rating2.RATING_PERCENTAGE:
    303                 return RatingCompat.newPercentageRating(rating2.getPercentRating());
    304             default:
    305                 return null;
    306         }
    307     }
    308 
    309     static Parcelable[] toMediaItem2ParcelableArray(List<MediaItem2> playlist) {
    310         if (playlist == null) {
    311             return null;
    312         }
    313         List<Parcelable> parcelableList = new ArrayList<>();
    314         for (int i = 0; i < playlist.size(); i++) {
    315             final MediaItem2 item = playlist.get(i);
    316             if (item != null) {
    317                 final Parcelable itemBundle = item.toBundle();
    318                 if (itemBundle != null) {
    319                     parcelableList.add(itemBundle);
    320                 }
    321             }
    322         }
    323         return parcelableList.toArray(new Parcelable[0]);
    324     }
    325 
    326     static List<MediaItem2> fromMediaItem2ParcelableArray(Parcelable[] itemParcelableList) {
    327         List<MediaItem2> playlist = new ArrayList<>();
    328         if (itemParcelableList != null) {
    329             for (int i = 0; i < itemParcelableList.length; i++) {
    330                 if (!(itemParcelableList[i] instanceof Bundle)) {
    331                     continue;
    332                 }
    333                 MediaItem2 item = MediaItem2.fromBundle((Bundle) itemParcelableList[i]);
    334                 if (item != null) {
    335                     playlist.add(item);
    336                 }
    337             }
    338         }
    339         return playlist;
    340     }
    341 
    342     static Parcelable[] toCommandButtonParcelableArray(List<CommandButton> layout) {
    343         if (layout == null) {
    344             return null;
    345         }
    346         List<Bundle> layoutBundles = new ArrayList<>();
    347         for (int i = 0; i < layout.size(); i++) {
    348             Bundle bundle = layout.get(i).toBundle();
    349             if (bundle != null) {
    350                 layoutBundles.add(bundle);
    351             }
    352         }
    353         return layoutBundles.toArray(new Parcelable[0]);
    354     }
    355 
    356     static List<CommandButton> fromCommandButtonParcelableArray(Parcelable[] list) {
    357         List<CommandButton> layout = new ArrayList<>();
    358         if (layout != null) {
    359             for (int i = 0; i < list.length; i++) {
    360                 if (!(list[i] instanceof Bundle)) {
    361                     continue;
    362                 }
    363                 CommandButton button = CommandButton.fromBundle((Bundle) list[i]);
    364                 if (button != null) {
    365                     layout.add(button);
    366                 }
    367             }
    368         }
    369         return layout;
    370     }
    371 
    372     static List<Bundle> toBundleList(Parcelable[] array) {
    373         if (array == null) {
    374             return null;
    375         }
    376         List<Bundle> bundleList = new ArrayList<>();
    377         for (Parcelable p : array) {
    378             bundleList.add((Bundle) p);
    379         }
    380         return bundleList;
    381     }
    382 
    383     static int createPlaybackStateCompatState(int playerState, int bufferingState) {
    384         switch (playerState) {
    385             case MediaPlayerInterface.PLAYER_STATE_PLAYING:
    386                 switch (bufferingState) {
    387                     case MediaPlayerInterface.BUFFERING_STATE_BUFFERING_AND_STARVED:
    388                         return PlaybackStateCompat.STATE_BUFFERING;
    389                 }
    390                 return PlaybackStateCompat.STATE_PLAYING;
    391             case MediaPlayerInterface.PLAYER_STATE_PAUSED:
    392                 return PlaybackStateCompat.STATE_PAUSED;
    393             case MediaPlayerInterface.PLAYER_STATE_IDLE:
    394                 return PlaybackStateCompat.STATE_NONE;
    395             case MediaPlayerInterface.PLAYER_STATE_ERROR:
    396                 return PlaybackStateCompat.STATE_ERROR;
    397         }
    398         // For unknown value
    399         return PlaybackStateCompat.STATE_ERROR;
    400     }
    401 
    402     static int toPlayerState(int playbackStateCompatState) {
    403         switch (playbackStateCompatState) {
    404             case PlaybackStateCompat.STATE_ERROR:
    405                 return MediaPlayerInterface.PLAYER_STATE_ERROR;
    406             case PlaybackStateCompat.STATE_NONE:
    407                 return MediaPlayerInterface.PLAYER_STATE_IDLE;
    408             case PlaybackStateCompat.STATE_PAUSED:
    409             case PlaybackStateCompat.STATE_STOPPED:
    410             case PlaybackStateCompat.STATE_BUFFERING: // means paused for buffering.
    411                 return MediaPlayerInterface.PLAYER_STATE_PAUSED;
    412             case PlaybackStateCompat.STATE_FAST_FORWARDING:
    413             case PlaybackStateCompat.STATE_PLAYING:
    414             case PlaybackStateCompat.STATE_REWINDING:
    415             case PlaybackStateCompat.STATE_SKIPPING_TO_NEXT:
    416             case PlaybackStateCompat.STATE_SKIPPING_TO_PREVIOUS:
    417             case PlaybackStateCompat.STATE_SKIPPING_TO_QUEUE_ITEM:
    418             case PlaybackStateCompat.STATE_CONNECTING: // Note: there's no perfect match for this.
    419                 return MediaPlayerInterface.PLAYER_STATE_PLAYING;
    420         }
    421         return MediaPlayerInterface.PLAYER_STATE_ERROR;
    422     }
    423 
    424     static boolean isDefaultLibraryRootHint(Bundle bundle) {
    425         return bundle != null && bundle.getBoolean(MediaConstants2.ROOT_EXTRA_DEFAULT, false);
    426     }
    427 
    428     static Bundle createBundle(Bundle bundle) {
    429         return (bundle == null) ? new Bundle() : new Bundle(bundle);
    430     }
    431 }
    432