Android Open Source - PlayTunes Remote Control Client Compat






From Project

Back to project page PlayTunes.

License

The source code is released under:

Copyright (c) 2014, Impeccable Labs, LLC. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions ar...

If you think the Android project PlayTunes listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (C) 2011 The Android Open Source Project
 */*from   www . j  av a2 s  .  co m*/
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.ideabag.playtunes.media;

import android.app.PendingIntent;
import android.graphics.Bitmap;
import android.os.Looper;
import android.util.Log;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * RemoteControlClient enables exposing information meant to be consumed by remote controls capable
 * of displaying metadata, artwork and media transport control buttons. A remote control client
 * object is associated with a media button event receiver. This event receiver must have been
 * previously registered with
 * {@link android.media.AudioManager#registerMediaButtonEventReceiver(android.content.ComponentName)}
 * before the RemoteControlClient can be registered through
 * {@link android.media.AudioManager#registerRemoteControlClient(android.media.RemoteControlClient)}.
 */
@SuppressWarnings({"rawtypes", "unchecked"})
public class RemoteControlClientCompat {

    private static final String TAG = "RemoteControlCompat";

    private static Class sRemoteControlClientClass;

    // RCC short for RemoteControlClient
    private static Method sRCCEditMetadataMethod;
    private static Method sRCCSetPlayStateMethod;
    private static Method sRCCSetTransportControlFlags;

    private static boolean sHasRemoteControlAPIs = false;

    static {
        try {
            ClassLoader classLoader = RemoteControlClientCompat.class.getClassLoader();
            sRemoteControlClientClass = getActualRemoteControlClientClass(classLoader);
            // dynamically populate the playstate and flag values in case they change
            // in future versions.
            for (Field field : RemoteControlClientCompat.class.getFields()) {
                try {
                    Field realField = sRemoteControlClientClass.getField(field.getName());
                    Object realValue = realField.get(null);
                    field.set(null, realValue);
                } catch (NoSuchFieldException e) {
                    Log.w(TAG, "Could not get real field: " + field.getName());
                } catch (IllegalArgumentException e) {
                    Log.w(TAG, "Error trying to pull field value for: " + field.getName()
                            + " " + e.getMessage());
                } catch (IllegalAccessException e) {
                    Log.w(TAG, "Error trying to pull field value for: " + field.getName()
                            + " " + e.getMessage());
                }
            }

            // get the required public methods on RemoteControlClient
            sRCCEditMetadataMethod = sRemoteControlClientClass.getMethod("editMetadata",
                    boolean.class);
            sRCCSetPlayStateMethod = sRemoteControlClientClass.getMethod("setPlaybackState",
                    int.class);
            sRCCSetTransportControlFlags = sRemoteControlClientClass.getMethod(
                    "setTransportControlFlags", int.class);

            sHasRemoteControlAPIs = true;
        } catch (ClassNotFoundException e) {
            // Silently fail when running on an OS before ICS.
        } catch (NoSuchMethodException e) {
            // Silently fail when running on an OS before ICS.
        } catch (IllegalArgumentException e) {
            // Silently fail when running on an OS before ICS.
        } catch (SecurityException e) {
            // Silently fail when running on an OS before ICS.
        }
    }

    public static Class getActualRemoteControlClientClass(ClassLoader classLoader)
            throws ClassNotFoundException {
        return classLoader.loadClass("android.media.RemoteControlClient");
    }

    private Object mActualRemoteControlClient;

    public RemoteControlClientCompat(PendingIntent pendingIntent) {
        if (!sHasRemoteControlAPIs) {
            return;
        }
        try {
            mActualRemoteControlClient =
                    sRemoteControlClientClass.getConstructor(PendingIntent.class)
                            .newInstance(pendingIntent);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public RemoteControlClientCompat(PendingIntent pendingIntent, Looper looper) {
        if (!sHasRemoteControlAPIs) {
            return;
        }

        try {
            mActualRemoteControlClient =
                    sRemoteControlClientClass.getConstructor(PendingIntent.class, Looper.class)
                            .newInstance(pendingIntent, looper);
        } catch (Exception e) {
            Log.e(TAG, "Error creating new instance of " + sRemoteControlClientClass.getName(), e);
        }
    }

    /**
     * Class used to modify metadata in a {@link android.media.RemoteControlClient} object. Use
     * {@link android.media.RemoteControlClient#editMetadata(boolean)} to create an instance of an
     * editor, on which you set the metadata for the RemoteControlClient instance. Once all the
     * information has been set, use {@link #apply()} to make it the new metadata that should be
     * displayed for the associated client. Once the metadata has been "applied", you cannot reuse
     * this instance of the MetadataEditor.
     */
    public class MetadataEditorCompat {

        private Method mPutStringMethod;
        private Method mPutBitmapMethod;
        private Method mPutLongMethod;
        private Method mClearMethod;
        private Method mApplyMethod;

        private Object mActualMetadataEditor;

        /**
         * The metadata key for the content artwork / album art.
         */
        public final static int METADATA_KEY_ARTWORK = 100;

        private MetadataEditorCompat(Object actualMetadataEditor) {
            if (sHasRemoteControlAPIs && actualMetadataEditor == null) {
                throw new IllegalArgumentException("Remote Control API's exist, " +
                        "should not be given a null MetadataEditor");
            }
            if (sHasRemoteControlAPIs) {
                Class metadataEditorClass = actualMetadataEditor.getClass();

                try {
                    mPutStringMethod = metadataEditorClass.getMethod("putString",
                            int.class, String.class);
                    mPutBitmapMethod = metadataEditorClass.getMethod("putBitmap",
                            int.class, Bitmap.class);
                    mPutLongMethod = metadataEditorClass.getMethod("putLong",
                            int.class, long.class);
                    mClearMethod = metadataEditorClass.getMethod("clear", new Class[]{});
                    mApplyMethod = metadataEditorClass.getMethod("apply", new Class[]{});
                } catch (Exception e) {
                    throw new RuntimeException(e.getMessage(), e);
                }
            }
            mActualMetadataEditor = actualMetadataEditor;
        }

        /**
         * Adds textual information to be displayed.
         * Note that none of the information added after {@link #apply()} has been called,
         * will be displayed.
         * @param key The identifier of a the metadata field to set. Valid values are
         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER}.
         * @param value The text for the given key, or {@code null} to signify there is no valid
         *      information for the field.
         * @return Returns a reference to the same MetadataEditor object, so you can chain put
         *      calls together.
         */
        public MetadataEditorCompat putString(int key, String value) {
            if (sHasRemoteControlAPIs) {
                try {
                    mPutStringMethod.invoke(mActualMetadataEditor, key, value);
                } catch (Exception e) {
                    throw new RuntimeException(e.getMessage(), e);
                }
            }
            return this;
        }

        /**
         * Sets the album / artwork picture to be displayed on the remote control.
         * @param key the identifier of the bitmap to set. The only valid value is
         *      {@link #METADATA_KEY_ARTWORK}
         * @param bitmap The bitmap for the artwork, or null if there isn't any.
         * @return Returns a reference to the same MetadataEditor object, so you can chain put
         *      calls together.
         * @throws IllegalArgumentException
         * @see android.graphics.Bitmap
         */
        public MetadataEditorCompat putBitmap(int key, Bitmap bitmap) {
            if (sHasRemoteControlAPIs) {
                try {
                    mPutBitmapMethod.invoke(mActualMetadataEditor, key, bitmap);
                } catch (Exception e) {
                    throw new RuntimeException(e.getMessage(), e);
                }
            }
            return this;
        }

        /**
         * Adds numerical information to be displayed.
         * Note that none of the information added after {@link #apply()} has been called,
         * will be displayed.
         * @param key the identifier of a the metadata field to set. Valid values are
         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
         *      expressed in milliseconds),
         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
         * @param value The long value for the given key
         * @return Returns a reference to the same MetadataEditor object, so you can chain put
         *      calls together.
         * @throws IllegalArgumentException
         */
        public MetadataEditorCompat putLong(int key, long value) {
            if (sHasRemoteControlAPIs) {
                try {
                    mPutLongMethod.invoke(mActualMetadataEditor, key, value);
                } catch (Exception e) {
                    throw new RuntimeException(e.getMessage(), e);
                }
            }
            return this;
        }

        /**
         * Clears all the metadata that has been set since the MetadataEditor instance was
         * created with {@link android.media.RemoteControlClient#editMetadata(boolean)}.
         */
        public void clear() {
            if (sHasRemoteControlAPIs) {
                try {
                    mClearMethod.invoke(mActualMetadataEditor, (Object[]) null);
                } catch (Exception e) {
                    throw new RuntimeException(e.getMessage(), e);
                }
            }
        }

        /**
         * Associates all the metadata that has been set since the MetadataEditor instance was
         * created with {@link android.media.RemoteControlClient#editMetadata(boolean)}, or since
         * {@link #clear()} was called, with the RemoteControlClient. Once "applied", this
         * MetadataEditor cannot be reused to edit the RemoteControlClient's metadata.
         */
        public void apply() {
            if (sHasRemoteControlAPIs) {
                try {
                    mApplyMethod.invoke(mActualMetadataEditor, (Object[]) null);
                } catch (Exception e) {
                    throw new RuntimeException(e.getMessage(), e);
                }
            }
        }
    }

    /**
     * Creates a {@link android.media.RemoteControlClient.MetadataEditor}.
     * @param startEmpty Set to false if you want the MetadataEditor to contain the metadata that
     *     was previously applied to the RemoteControlClient, or true if it is to be created empty.
     * @return a new MetadataEditor instance.
     */
    public MetadataEditorCompat editMetadata(boolean startEmpty) {
        Object metadataEditor;
        if (sHasRemoteControlAPIs) {
            try {
                metadataEditor = sRCCEditMetadataMethod.invoke(mActualRemoteControlClient,
                        startEmpty);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else {
            metadataEditor = null;
        }
        return new MetadataEditorCompat(metadataEditor);
    }

    /**
     * Sets the current playback state.
     * @param state The current playback state, one of the following values:
     *       {@link android.media.RemoteControlClient#PLAYSTATE_STOPPED},
     *       {@link android.media.RemoteControlClient#PLAYSTATE_PAUSED},
     *       {@link android.media.RemoteControlClient#PLAYSTATE_PLAYING},
     *       {@link android.media.RemoteControlClient#PLAYSTATE_FAST_FORWARDING},
     *       {@link android.media.RemoteControlClient#PLAYSTATE_REWINDING},
     *       {@link android.media.RemoteControlClient#PLAYSTATE_SKIPPING_FORWARDS},
     *       {@link android.media.RemoteControlClient#PLAYSTATE_SKIPPING_BACKWARDS},
     *       {@link android.media.RemoteControlClient#PLAYSTATE_BUFFERING},
     *       {@link android.media.RemoteControlClient#PLAYSTATE_ERROR}.
     */
    public void setPlaybackState(int state) {
        if (sHasRemoteControlAPIs) {
            try {
                sRCCSetPlayStateMethod.invoke(mActualRemoteControlClient, state);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * Sets the flags for the media transport control buttons that this client supports.
     * @param transportControlFlags A combination of the following flags:
     *      {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PREVIOUS},
     *      {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_REWIND},
     *      {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PLAY},
     *      {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PLAY_PAUSE},
     *      {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PAUSE},
     *      {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_STOP},
     *      {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_FAST_FORWARD},
     *      {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_NEXT}
     */
    public void setTransportControlFlags(int transportControlFlags) {
        if (sHasRemoteControlAPIs) {
            try {
                sRCCSetTransportControlFlags.invoke(mActualRemoteControlClient,
                        transportControlFlags);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public final Object getActualRemoteControlClientObject() {
        return mActualRemoteControlClient;
    }
}




Java Source Code List

com.ideabag.playtunes.PlaylistManager.java
com.ideabag.playtunes.DragNDrop.DragListener.java
com.ideabag.playtunes.DragNDrop.DragNDropListView.java
com.ideabag.playtunes.DragNDrop.DropListener.java
com.ideabag.playtunes.DragNDrop.RemoveListener.java
com.ideabag.playtunes.activity.MainActivity.java
com.ideabag.playtunes.activity.NowPlayingActivity.java
com.ideabag.playtunes.activity.SettingsActivity.java
com.ideabag.playtunes.adapter.AlbumListAdapter.java
com.ideabag.playtunes.adapter.AlbumsAllAdapter.java
com.ideabag.playtunes.adapter.AlbumsOneAdapter.java
com.ideabag.playtunes.adapter.ArtistAlbumsAdapter.java
com.ideabag.playtunes.adapter.ArtistAllSongsAdapter.java
com.ideabag.playtunes.adapter.ArtistListAdapter.java
com.ideabag.playtunes.adapter.ArtistSinglesAdapter.java
com.ideabag.playtunes.adapter.ArtistsAllAdapter.java
com.ideabag.playtunes.adapter.AsyncQueryAdapter.java
com.ideabag.playtunes.adapter.GenresAllAdapter.java
com.ideabag.playtunes.adapter.GenresOneAdapter.java
com.ideabag.playtunes.adapter.NavigationListAdapter.java
com.ideabag.playtunes.adapter.PlaylistsAllAdapter.java
com.ideabag.playtunes.adapter.PlaylistsOneAdapter.java
com.ideabag.playtunes.adapter.SongListAdapter.java
com.ideabag.playtunes.adapter.SongsAllAdapter.java
com.ideabag.playtunes.adapter.search.SearchAlbumsAdapter.java
com.ideabag.playtunes.adapter.search.SearchArtistsAdapter.java
com.ideabag.playtunes.adapter.search.SearchSongsAdapter.java
com.ideabag.playtunes.database.MediaQuery.java
com.ideabag.playtunes.dialog.AddToPlaylistDialogFragment.java
com.ideabag.playtunes.dialog.CreatePlaylistDialogFragment.java
com.ideabag.playtunes.dialog.FeedbackDialogFragment.java
com.ideabag.playtunes.dialog.PlaylistDeleteDialogFragment.java
com.ideabag.playtunes.dialog.PlaylistMenuDialogFragment.java
com.ideabag.playtunes.dialog.PlaylistRenameDialogFragment.java
com.ideabag.playtunes.dialog.RateAppDialogFragment.java
com.ideabag.playtunes.dialog.SongMenuDialogFragment.java
com.ideabag.playtunes.fragment.AlbumsAllFragment.java
com.ideabag.playtunes.fragment.AlbumsOneFragment.java
com.ideabag.playtunes.fragment.ArtistSinglesFragment.java
com.ideabag.playtunes.fragment.ArtistsAllFragment.java
com.ideabag.playtunes.fragment.ArtistsOneFragment.java
com.ideabag.playtunes.fragment.FooterControlsFragment.java
com.ideabag.playtunes.fragment.GenresAllFragment.java
com.ideabag.playtunes.fragment.GenresOneFragment.java
com.ideabag.playtunes.fragment.MusicBrowserFragment.java
com.ideabag.playtunes.fragment.NavigationDrawerFragment.java
com.ideabag.playtunes.fragment.NavigationFragment.java
com.ideabag.playtunes.fragment.PlaylistsAllFragment.java
com.ideabag.playtunes.fragment.PlaylistsOneFragment.java
com.ideabag.playtunes.fragment.SaveScrollListFragment.java
com.ideabag.playtunes.fragment.SongsFragment.java
com.ideabag.playtunes.fragment.TrackProgressFragment.java
com.ideabag.playtunes.fragment.search.SearchAlbumsFragment.java
com.ideabag.playtunes.fragment.search.SearchAllFragment.java
com.ideabag.playtunes.fragment.search.SearchArtistsFragment.java
com.ideabag.playtunes.fragment.search.SearchFragment.java
com.ideabag.playtunes.fragment.search.SearchSongsFragment.java
com.ideabag.playtunes.fragment.search.SearchSuggestionsFragment.java
com.ideabag.playtunes.media.AudioFocusHelper.java
com.ideabag.playtunes.media.MusicFocusable.java
com.ideabag.playtunes.media.MusicIntentReceiver.java
com.ideabag.playtunes.media.PlaylistMediaPlayer.java
com.ideabag.playtunes.media.RemoteControlClientCompat.java
com.ideabag.playtunes.media.RemoteControlHelper.java
com.ideabag.playtunes.service.LockscreenManager.java
com.ideabag.playtunes.service.MusicPlayerService.java
com.ideabag.playtunes.service.PlaybackNotification.java
com.ideabag.playtunes.util.AdmobUtil.java
com.ideabag.playtunes.util.AlbumSongsCountTask.java
com.ideabag.playtunes.util.AsyncDrawable.java
com.ideabag.playtunes.util.BitmapWorkerTask.java
com.ideabag.playtunes.util.CheckRemoteVersionFileTask.java
com.ideabag.playtunes.util.DrawerLayout.java
com.ideabag.playtunes.util.GAEvent.java
com.ideabag.playtunes.util.IMusicBrowser.java
com.ideabag.playtunes.util.ISearchableAdapter.java
com.ideabag.playtunes.util.LoadAlbumStackTask.java
com.ideabag.playtunes.util.MergeAdapter.java
com.ideabag.playtunes.util.QueryCountTask.java
com.ideabag.playtunes.util.SackOfViewsAdapter.java
com.ideabag.playtunes.util.SearchHistory.java
com.ideabag.playtunes.util.StarToggleTask.java
com.ideabag.playtunes.util.TrackerSingleton.java