AAOS'de medya kartı uygulama

Medya kartı, başlık ve albüm kapağı gibi medya meta verilerini gösteren, Oynat, Duraklat ve Atla gibi oynatma denetimlerinin yanı sıra üçüncü taraf medya uygulaması tarafından sağlanan özel işlemleri gösteren bağımsız bir ViewGroup'dur. Medya kartı, oynatma listesi gibi bir medya öğesi sırasını da gösterebilir.

Medya kartı

Medya kartı

Medya kartı

Şekil 1. Medya kartı örnek uygulamaları.

Medya kartları AAOS'te nasıl uygulanır?

Medya bilgilerini gösteren ViewGroup'lar, ViewGroup'u doldurmak için car-media-common kitaplık verileri modelinden (PlaybackViewModel) gelen LiveData güncellemelerini izler. Her LiveData güncellemesi, MediaItemMetadata, PlaybackStateWrapper ve MediaSource gibi değişen bir medya bilgisi alt kümesine karşılık gelir.

Bu yaklaşım, yinelenen koda yol açtığından (her istemci uygulaması, her LiveData parçasına gözlemci ekler ve güncellenen veriler birçok benzer görünüme atanır) PlaybackCardController'i oluşturduk.

PlaybackCardController

PlaybackCardController, medya kartı oluşturmaya yardımcı olmak için car-media-common kitaplığına eklendi. Bu, bir ViewGroup (mView), PlaybackViewModel (mDataModel), PlaybackCardViewModel (mViewModel) ve MediaItemsRepository örneği (mItemsRepository) ile oluşturulan herkese açık bir sınıftır.

setupController işlevinde, ViewGroup, mView.findViewById(R.id.xxx) ile kimliğe göre belirli görünümler için ayrıştırılır ve korunan View nesnelerine atanır.

private void getViewsFromWidget() {
        mTitle = mView.findViewById(R.id.title);
        mAlbumCover = mView.findViewById(R.id.album_art);
        mDescription = mView.findViewById(R.id.album_title);
        mLogo = mView.findViewById(R.id.content_format);

        mAppIcon = mView.findViewById(R.id.media_widget_app_icon);
        mAppName = mView.findViewById(R.id.media_widget_app_name);

         // ...
}

PlaybackViewModel kaynağından gelen her LiveData güncellemesi, korumalı bir yöntemle gözlemlenir ve alınan verilerle alakalı Görünümlerle etkileşim gerçekleştirir. Örneğin, MediaItemMetadata'teki bir gözlemci, mTitle TextView'de başlığı ayarlar ve MediaItemMetadata.ArtworkRef'ı albüm resmi ImageBinder mAlbumArtBinder'e iletir. Meta veriler null ise Görüntüleme Sayısı gizlenir. Denetleyicinin alt sınıfları gerekirse bu mantığı geçersiz kılabilir.

mDataModel.getMetadata().observe(mViewLifecycle, this::updateMetadata);
// ...

/** Update views with {@link MediaItemMetadata} */
protected void updateMetadata(MediaItemMetadata metadata) {
        if (metadata != null) {
            String defaultTitle = mView.getContext().getString(
                    R.string.metadata_default_title);
            updateTextViewAndVisibility(mTitle, metadata.getTitle(),    defaultTitle);
            updateTextViewAndVisibility(mSubtitle, metadata.getSubtitle());
            updateMediaLink(mSubtitleLinker,metadata.getSubtitleLinkMediaId());
            updateTextViewAndVisibility(mDescription, metadata.getDescription());
            updateMediaLink(mDescriptionLinker, metadata.getDescriptionLinkMediaId());
            updateMetadataAlbumCoverArtworkRef(metadata.getArtworkKey());
            updateMetadataLogoWithUri(metadata);
        } else {
            ViewUtils.setVisible(mTitle, false);
            ViewUtils.setVisible(mSubtitle, false);
            ViewUtils.setVisible(mAlbumCover, false);
            ViewUtils.setVisible(mDescription, false);
            ViewUtils.setVisible(mLogo, false);
        }
    }

PlaybackCardController'ı genişletin

Medya kartı oluşturmak isteyen istemci uygulamaları, her LiveData güncellemesinde ele almak istedikleri ek bir özellik varsa PlaybackCardController sınıfını genişletmelidir. AAOS'teki mevcut istemciler bu kalıbı izler. Öncelikle, MediaCardController gibi bir PlaybackCardController alt sınıfı oluşturulmalıdır. Ardından MediaCardController, PlaybackCardController sınıfını genişleten statik bir iç Builder sınıfı eklemelidir.

public class MediaCardController extends PlaybackCardController {

    // extra fields specific to MediaCardController

    /** Builder for {@link MediaCardController}. Overrides build() method to
     * return NowPlayingController rather than base {@link PlaybackCardController}
     */
    public static class Builder extends PlaybackCardController.Builder {

        @Override
        public MediaCardController build() {
            MediaCardController controller = new MediaCardController(this);
            controller.setupController();
            return controller;
        }
    }

    public MediaCardController(Builder builder) {
        super(builder);
    // any other function calls needed in constructor
    // ...

  }
}

PlaybackCardController veya alt sınıfını örneklendirin

LiveData gözlemcileri için bir LifecycleOwner'a sahip olmak amacıyla Controller sınıfı bir Fragment veya Activity'den oluşturulmalıdır.

mMediaCardController = (MediaCardController) new MediaCardController.Builder()
                    .setModels(mViewModel.getPlaybackViewModel(),
                            mViewModel,
                            mViewModel.getMediaItemsRepository())
                    .setViewGroup((ViewGroup) view)
                    .build();

mViewModel, PlaybackCardViewModel (veya alt sınıf) örneğidir.

Durumu Kaydetme İçin PlaybackCardViewModel

PlaybackCardViewModel, bir yapılandırma değişikliği (ör. kullanıcı bir tünelden geçerken açık temadan koyu temaya geçiş) olduğunda medya kartının içeriğini yeniden oluşturmak için kullanılması gereken, bir Fragment veya Activity'ye bağlı, durum kaydeden bir ViewModel'dir. Varsayılan PlaybackCardViewModel, oynatılmak üzere MediaModel örneklerini saklar. Bu örneklerden PlaybackViewModel ve MediaItemsRepository alınabilir. Sağlanan alıcı ve ayarlayıcılar aracılığıyla kuyruğun, geçmişin ve taşma menüsünün durumunu izlemek için PlaybackCardViewModel öğesini kullanın.

public class PlaybackCardViewModel extends AndroidViewModel {

    private MediaModels mModels;
    private boolean mNeedsInitialization = true;
    private boolean mQueueVisible = false;
    private boolean mHistoryVisible = false;
    private boolean mOverflowExpanded = false;

    public PlaybackCardViewModel(@NonNull Application application) {
        super(application);
    }

    /** Initialize the PlaybackCardViewModel */
    public void init(MediaModels models) {
        mModels = models;
        mNeedsInitialization = false;
    }

    /**
     * Returns whether the ViewModel needs to be initialized. The ViewModel may
     * need re-initialization if a config change occurs or if the system kills
     * the Fragment.
     */
    public boolean needsInitialization() {
        return mNeedsInitialization;
    }

    public MediaItemsRepository getMediaItemsRepository() {
        return mModels.getMediaItemsRepository();
    }

    public PlaybackViewModel getPlaybackViewModel() {
        return mModels.getPlaybackViewModel();
    }

    public MediaSourceViewModel getMediaSourceViewModel() {
        return mModels.getMediaSourceViewModel();
    }

    public void setQueueVisible(boolean visible) {
        mQueueVisible = visible;
    }

    public boolean getQueueVisible() {
        return mQueueVisible;
    }

    public void setHistoryVisible(boolean visible) {
        mHistoryVisible = visible;
    }

    public boolean getHistoryVisible() {
        return mHistoryVisible;
    }

    public void setOverflowExpanded(boolean expanded) {
        mOverflowExpanded = expanded;
    }

    public boolean getOverflowExpanded() {
        return mOverflowExpanded;
    }
}

Daha fazla eyaletin izlenmesi gerekiyorsa bu sınıf genişletilebilir.

Medya kartında sıra gösterme

PlaybackViewModel, MediaSource'un sırayı destekleyip desteklemediğini algılamak ve sıradaki MediaItemMetadata nesnelerinin listesini almak için LiveData API'leri sağlar. Bu API'ler, bir RecyclerView nesnesini doğrudan sıra bilgileriyle doldurmak için kullanılabilir olsa da bu işlemi kolaylaştırmak amacıyla car-media-common kitaplığına bir PlaybackQueueController sınıfı eklenmiştir. CarUiRecyclerView içindeki her öğenin düzeni, isteğe bağlı bir başlık düzeni olarak istemci uygulaması tarafından da belirtilir. İstemci uygulaması, özel UXR kısıtlamalarıyla sürüş durumunda kuyrukta gösterilen öğe sayısını da sınırlayabilir.

PlaybackQueueController kurucusu ve ayarlayıcıları aşağıdaki örnekte gösterilmektedir. queueResource ve headerResource düzen kaynakları, önceki durumda kapsayıcıda id queue_list içeren bir CarUiRecyclerView varsa ve son durumda kuyrukta bir başlık yoksa Resources.ID_NULL olarak iletilebilir.

   /**
    * Construct a PlaybackQueueController. If clients don't have a separate
    * layout for the queue, where the queue is already inflated within the
    * container, they should pass {@link Resources.ID_NULL} as the LayoutRes
    * resource. If clients don't require a UxrContentLimiter, they should pass
    * null for uxrContentLimiter and the int passed for uxrConfigurationId will
    * be ignored.
    */
    public PlaybackQueueController(
            ViewGroup container,
            @LayoutRes int queueResource,
            @LayoutRes int queueItemResource,
            @LayoutRes int headerResource,
            LifecycleOwner lifecycleOwner,
            PlaybackViewModel playbackViewModel,
            MediaItemsRepository itemsRepository,
            @Nullable LifeCycleObserverUxrContentLimiter uxrContentLimiter,
            int uxrConfigurationId) {
      // ...
    }

    public void setShowTimeForActiveQueueItem(boolean show) {
        mShowTimeForActiveQueueItem = show;
    }

    public void setShowIconForActiveQueueItem(boolean show) {
        mShowIconForActiveQueueItem = show;
    }

    public void setShowThumbnailForQueueItem(boolean show) {
        mShowThumbnailForQueueItem = show;
    }

    public void setShowSubtitleForQueueItem(boolean show) {
        mShowSubtitleForQueueItem = show;
    }

    /** Calls {@link RecyclerView#setVerticalFadingEdgeEnabled(boolean)} */
    public void setVerticalFadingEdgeLengthEnabled(boolean enabled) {
        mQueue.setVerticalFadingEdgeEnabled(enabled);
    }

    public void setCallback(PlaybackQueueCallback callback) {
        mPlaybackQueueCallback = callback;
    }

Her sıra öğesinin düzeni, göstermek istediği ve QueueViewHolder iç sınıfında kullanılanlara karşılık gelen Görünümlerin kimliklerini içermelidir.

QueueViewHolder(View itemView) {
            super(itemView);
            mView = itemView;
            mThumbnailContainer = itemView.findViewById(R.id.thumbnail_container);
            mThumbnail = itemView.findViewById(R.id.thumbnail);
            mSpacer = itemView.findViewById(R.id.spacer);
            mTitle = itemView.findViewById(R.id.queue_list_item_title);
            mSubtitle = itemView.findViewById(R.id.queue_list_item_subtitle);
            mCurrentTime = itemView.findViewById(R.id.current_time);
            mMaxTime = itemView.findViewById(R.id.max_time);
            mTimeSeparator = itemView.findViewById(R.id.separator);
            mActiveIcon = itemView.findViewById(R.id.now_playing_icon);

            // ...
}

PlaybackCardController (veya alt sınıf) ile oluşturulan bir medya kartında sıra göstermek için PlaybackQueueController, PlaybackCardController yapıcısında sırasıyla PlaybackViewModel ve MediaItemsRepository örnekleri için mDataModel ve mItemsRepository kullanılarak oluşturulabilir.

Daha önce oynatılan MediaSources'ın geçmişini gösterme

Bu bölümde, daha önce oynatılan medya kaynaklarının geçmişini nasıl göstereceğinizi ve bu geçmişi nasıl bulacağınızı öğreneceksiniz.

PlaybackCardViewModel API ile geçmiş listesini alma

PlaybackCardViewModel, medya geçmişi listesini almak için getHistoryList() adlı bir LiveData API sağlar. Daha önce oynatılan MediaSource öğelerinin listesini içeren bir LiveData döndürür. Bu veriler, bir CarUiRecyclerView nesnesini doldurmak için kullanılabilir. PlaybackQueueController'e benzer şekilde, işlemi kolaylaştırmak için car-media-common kitaplığına PlaybackHistoryController adlı bir sınıf eklendi.

public class PlaybackCardViewModel extends AndroidViewModel {

    public PlaybackCardViewModel(@NonNull Application application) {
    }

    /** Initialize the PlaybackCardViewModel */
    public void init(MediaModels models) {
    }

    public LiveData<List<MediaSource>> getHistoryList() {
        return mHistoryListData;
    }
}

PlaybackHistoryController ile geçmiş kullanıcı arayüzü

Geçmiş verilerini bir CarUiRecyclerView ile doldurmak için yeni PlaybackHistoryController'ü kullanın. Bu sınıfın kurucuları ve ana işlevleri aşağıdaki gibidir. İstemci uygulamasından iletilen kapsayıcı, history_list kimlikli bir CarUiRecyclerView içermelidir. CarUiRecyclerView liste öğelerini ve isteğe bağlı bir üstbilgi gösterir. Hem liste öğesi hem de başlık için düzenler istemci uygulamasından iletilebilir. Resources.ID_NULL, headerResource olarak ayarlanırsa başlık gösterilmez. PlaybackCardViewModel, kontrolöre aktarıldıktan sonra playbackCardViewModel.getHistoryList()'den alınan LiveData<List<MediaSource>>'ı izler.

public class PlaybackHistoryController {

    public PlaybackHistoryController(
            LifecycleOwner lifecycleOwner,
            PlaybackCardViewModel playbackCardViewModel,
            ViewGroup container,
            @LayoutRes int itemResource,
            @LayoutRes int headerResource,
            int uxrConfigurationId) {
    }

    /**
     * Renders the view.
     */
    public void setupView() {
    }
}

Her öğenin düzeni, göstermek istediği görünümlerin kimliklerini içermelidir. Bu kimlikler, ViewHolder iç sınıfında kullanılanlara karşılık gelmelidir.

HistoryItemViewHolder(View itemView) {
            super(itemView);
            mContext = itemView.getContext();
            mActiveView = itemView.findViewById(R.id.history_card_container_active);
            mInactiveView = itemView.findViewById(R.id.history_card_container_inactive);
            mMetadataTitleView = itemView.findViewById(R.id.history_card_title_active);
            mAdditionalInfo = itemView.findViewById(R.id.history_card_subtitle_active);
            mAppIcon = itemView.findViewById(R.id.history_card_app_thumbnail);
            mAlbumArt = itemView.findViewById(R.id.history_card_album_art);
            mAppTitleInactive = itemView.findViewById(R.id.history_card_app_title_inactive);
            mAppIconInactive = itemView.findViewById(R.id.history_item_app_icon_inactive);
// ...
}

PlaybackCardController (veya alt sınıf) ile oluşturulan bir medya kartında geçmiş listesi göstermek için PlaybackHistoryController, PlaybackCardController'ün kurucusunda oluşturulabilir.