| /* |
| * Copyright (C) 2014 Google Inc. All Rights Reserved. |
| * |
| * 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.example.android.musicservicedemo; |
| |
| import android.app.SearchManager; |
| import android.app.Service; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.UriMatcher; |
| import android.content.res.Resources.NotFoundException; |
| import android.database.MatrixCursor; |
| import android.graphics.Bitmap; |
| import android.media.AudioManager; |
| import android.media.MediaDescription; |
| import android.media.MediaPlayer; |
| import android.media.MediaPlayer.OnCompletionListener; |
| import android.media.MediaPlayer.OnErrorListener; |
| import android.media.MediaPlayer.OnPreparedListener; |
| import android.media.browse.MediaBrowser; |
| import android.service.media.MediaBrowserService; |
| import android.service.media.MediaBrowserService.BrowserRoot; |
| import android.media.session.MediaSession; |
| import android.net.Uri; |
| import android.net.wifi.WifiManager; |
| import android.net.wifi.WifiManager.WifiLock; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.os.IBinder; |
| import android.os.Message; |
| import android.os.PowerManager; |
| import android.os.RemoteException; |
| import android.os.SystemClock; |
| import android.util.Log; |
| |
| import com.example.android.musicservicedemo.browser.MusicProvider; |
| import com.example.android.musicservicedemo.browser.MusicProviderTask; |
| import com.example.android.musicservicedemo.browser.MusicProviderTaskListener; |
| import com.example.android.musicservicedemo.browser.MusicTrack; |
| |
| import org.json.JSONException; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * Service that implements MediaBrowserService and returns our menu hierarchy. |
| */ |
| public class BrowserService extends MediaBrowserService { |
| private static final String TAG = "BrowserService"; |
| |
| // URI paths for browsing music |
| public static final String BROWSE_ROOT_BASE_PATH = "browse"; |
| public static final String NOW_PLAYING_PATH = "now_playing"; |
| public static final String PIANO_BASE_PATH = "piano"; |
| public static final String VOICE_BASE_PATH = "voice"; |
| |
| // Content URIs |
| public static final String AUTHORITY = "com.example.android.automotive.musicplayer"; |
| public static final Uri BASE_URI = Uri.parse("content://" + AUTHORITY); |
| public static final Uri BROWSE_URI = Uri.withAppendedPath(BASE_URI, BROWSE_ROOT_BASE_PATH); |
| |
| // URI matcher constants for browsing paths |
| public static final int BROWSE_ROOT = 1; |
| public static final int NOW_PLAYING = 2; |
| public static final int PIANO = 3; |
| public static final int VOICE = 4; |
| |
| // Map the the URI paths with the URI matcher constants |
| private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); |
| static { |
| sUriMatcher.addURI(AUTHORITY, BROWSE_ROOT_BASE_PATH, BROWSE_ROOT); |
| sUriMatcher.addURI(AUTHORITY, NOW_PLAYING_PATH, NOW_PLAYING); |
| sUriMatcher.addURI(AUTHORITY, PIANO_BASE_PATH, PIANO); |
| sUriMatcher.addURI(AUTHORITY, VOICE_BASE_PATH, VOICE); |
| } |
| |
| // Media metadata that will be provided for a media container |
| public static final String[] MEDIA_CONTAINER_PROJECTION = { |
| "uri", |
| "title", |
| "subtitle", |
| "image_uri", |
| "supported_actions" |
| }; |
| |
| // MusicProvider will download the music catalog |
| private MusicProvider mMusicProvider; |
| |
| private MediaSession mSession; |
| |
| @Override |
| public void onCreate() { |
| super.onCreate(); |
| |
| mSession = new MediaSession(this, "com.example.android.musicservicedemo.BrowserService"); |
| setSessionToken(mSession.getSessionToken()); |
| } |
| |
| @Override |
| public void onDestroy() { |
| super.onDestroy(); |
| } |
| |
| @Override |
| public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) { |
| return new BrowserRoot(BROWSE_URI.toString(), null); |
| } |
| |
| @Override |
| public void onLoadChildren(final String parentId, |
| final Result<List<MediaBrowser.MediaItem>> result) { |
| new Handler().postDelayed(new Runnable() { |
| public void run() { |
| final ArrayList<MediaBrowser.MediaItem> list = new ArrayList(); |
| |
| for (int i=0; i<10; i++) { |
| MediaDescription.Builder bob = new MediaDescription.Builder(); |
| bob.setTitle("Title " + i); |
| bob.setSubtitle("Summary " + i); |
| bob.setMediaId(Uri.withAppendedPath(BASE_URI, |
| Integer.toString(i)).toString()); |
| list.add(new MediaBrowser.MediaItem(bob.build(), |
| MediaBrowser.MediaItem.FLAG_BROWSABLE)); |
| } |
| |
| result.sendResult(list); |
| } |
| }, 2000); |
| result.detach(); |
| } |
| |
| /* |
| @Override |
| public void query(final Query query, final IMetadataResultHandler metadataResultHandler, |
| final IErrorHandler errorHandler) |
| throws RemoteException { |
| Log.d(TAG, "query: " + query); |
| Utils.checkNotNull(query); |
| Utils.checkNotNull(metadataResultHandler); |
| Utils.checkNotNull(errorHandler); |
| |
| // Handle async response |
| new Thread(new Runnable() { |
| public void run() { |
| try { |
| // Pre-load the list of music |
| List<MusicTrack> musicTracks = getMusicList(); |
| if (musicTracks == null) { |
| notifyListenersOnPlaybackStateUpdate(getCurrentPlaybackState()); |
| errorHandler.onError(new Error(Error.UNKNOWN, |
| getString(R.string.music_error))); |
| return; |
| } |
| |
| final Uri uri = query.getUri(); |
| int match = sUriMatcher.match(uri); |
| Log.d(TAG, "Queried: " + uri + "; match: " + match); |
| switch (match) { |
| case BROWSE_ROOT: |
| { |
| Log.d(TAG, "Browse_root"); |
| |
| try { |
| MatrixCursor matrixCursor = mMusicProvider |
| .getRootContainerCurser(); |
| DataHolder holder = new DataHolder(MEDIA_CONTAINER_PROJECTION, |
| matrixCursor, null); |
| |
| Log.d(TAG, "on metadata response called " + holder.getCount()); |
| metadataResultHandler.onMetadataResponse(holder); |
| } catch (RemoteException e) { |
| Log.w(TAG, "Error delivering metadata in the callback.", e); |
| } |
| break; |
| } |
| case NOW_PLAYING: |
| { |
| try { |
| Log.d(TAG, "query NOW_PLAYING"); |
| MatrixCursor matrixCursor = mMusicProvider |
| .getRootItemCursor( |
| PIANO); |
| DataHolder holder = new DataHolder(MEDIA_CONTAINER_PROJECTION, |
| matrixCursor, null); |
| Log.d(TAG, "on metadata response called " + holder.getCount()); |
| metadataResultHandler.onMetadataResponse(holder); |
| } catch (RemoteException e) { |
| Log.w(TAG, "Error querying NOW_PLAYING"); |
| } |
| break; |
| } |
| case PIANO: |
| { |
| try { |
| Log.d(TAG, "query PIANO"); |
| MatrixCursor matrixCursor = mMusicProvider |
| .getRootItemCursor( |
| PIANO); |
| DataHolder holder = new DataHolder(MEDIA_CONTAINER_PROJECTION, |
| matrixCursor, null); |
| Log.d(TAG, "on metadata response called " + holder.getCount()); |
| metadataResultHandler.onMetadataResponse(holder); |
| } catch (RemoteException e) { |
| Log.w(TAG, "Error querying PIANO"); |
| } |
| break; |
| } |
| case VOICE: |
| { |
| try { |
| Log.d(TAG, "query VOICE"); |
| MatrixCursor matrixCursor = mMusicProvider |
| .getRootItemCursor( |
| VOICE); |
| DataHolder holder = new DataHolder(MEDIA_CONTAINER_PROJECTION, |
| matrixCursor, null); |
| Log.d(TAG, "on metadata response called " + holder.getCount()); |
| metadataResultHandler.onMetadataResponse(holder); |
| } catch (RemoteException e) { |
| Log.w(TAG, "Error querying VOICE"); |
| } |
| break; |
| } |
| default: |
| { |
| Log.w(TAG, "Skipping unmatched URI: " + uri); |
| } |
| } |
| } catch (NotFoundException e) { |
| Log.e(TAG, "::run:", e); |
| } catch (RemoteException e) { |
| Log.e(TAG, "::run:", e); |
| } |
| } // end run |
| }).start(); |
| } |
| |
| */ |
| } |