1 /* 2 * Copyright (C) 2014 Google Inc. All Rights Reserved. 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.example.android.musicservicedemo; 18 19 import android.app.SearchManager; 20 import android.app.Service; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.UriMatcher; 24 import android.content.res.Resources.NotFoundException; 25 import android.database.MatrixCursor; 26 import android.graphics.Bitmap; 27 import android.media.AudioManager; 28 import android.media.MediaDescription; 29 import android.media.MediaPlayer; 30 import android.media.MediaPlayer.OnCompletionListener; 31 import android.media.MediaPlayer.OnErrorListener; 32 import android.media.MediaPlayer.OnPreparedListener; 33 import android.media.browse.MediaBrowser; 34 import android.service.media.MediaBrowserService; 35 import android.service.media.MediaBrowserService.BrowserRoot; 36 import android.media.session.MediaSession; 37 import android.net.Uri; 38 import android.net.wifi.WifiManager; 39 import android.net.wifi.WifiManager.WifiLock; 40 import android.os.Bundle; 41 import android.os.Handler; 42 import android.os.IBinder; 43 import android.os.Message; 44 import android.os.PowerManager; 45 import android.os.RemoteException; 46 import android.os.SystemClock; 47 import android.util.Log; 48 49 import com.example.android.musicservicedemo.browser.MusicProvider; 50 import com.example.android.musicservicedemo.browser.MusicProviderTask; 51 import com.example.android.musicservicedemo.browser.MusicProviderTaskListener; 52 import com.example.android.musicservicedemo.browser.MusicTrack; 53 54 import org.json.JSONException; 55 56 import java.io.IOException; 57 import java.util.ArrayList; 58 import java.util.List; 59 60 /** 61 * Service that implements MediaBrowserService and returns our menu hierarchy. 62 */ 63 public class BrowserService extends MediaBrowserService { 64 private static final String TAG = "BrowserService"; 65 66 // URI paths for browsing music 67 public static final String BROWSE_ROOT_BASE_PATH = "browse"; 68 public static final String NOW_PLAYING_PATH = "now_playing"; 69 public static final String PIANO_BASE_PATH = "piano"; 70 public static final String VOICE_BASE_PATH = "voice"; 71 72 // Content URIs 73 public static final String AUTHORITY = "com.example.android.automotive.musicplayer"; 74 public static final Uri BASE_URI = Uri.parse("content://" + AUTHORITY); 75 public static final Uri BROWSE_URI = Uri.withAppendedPath(BASE_URI, BROWSE_ROOT_BASE_PATH); 76 77 // URI matcher constants for browsing paths 78 public static final int BROWSE_ROOT = 1; 79 public static final int NOW_PLAYING = 2; 80 public static final int PIANO = 3; 81 public static final int VOICE = 4; 82 83 // Map the the URI paths with the URI matcher constants 84 private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 85 static { 86 sUriMatcher.addURI(AUTHORITY, BROWSE_ROOT_BASE_PATH, BROWSE_ROOT); 87 sUriMatcher.addURI(AUTHORITY, NOW_PLAYING_PATH, NOW_PLAYING); 88 sUriMatcher.addURI(AUTHORITY, PIANO_BASE_PATH, PIANO); 89 sUriMatcher.addURI(AUTHORITY, VOICE_BASE_PATH, VOICE); 90 } 91 92 // Media metadata that will be provided for a media container 93 public static final String[] MEDIA_CONTAINER_PROJECTION = { 94 "uri", 95 "title", 96 "subtitle", 97 "image_uri", 98 "supported_actions" 99 }; 100 101 // MusicProvider will download the music catalog 102 private MusicProvider mMusicProvider; 103 104 private MediaSession mSession; 105 106 @Override 107 public void onCreate() { 108 super.onCreate(); 109 110 mSession = new MediaSession(this, "com.example.android.musicservicedemo.BrowserService"); 111 setSessionToken(mSession.getSessionToken()); 112 } 113 114 @Override 115 public void onDestroy() { 116 super.onDestroy(); 117 } 118 119 @Override 120 public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) { 121 return new BrowserRoot(BROWSE_URI.toString(), null); 122 } 123 124 @Override 125 public void onLoadChildren(final String parentId, 126 final Result<List<MediaBrowser.MediaItem>> result) { 127 new Handler().postDelayed(new Runnable() { 128 public void run() { 129 final ArrayList<MediaBrowser.MediaItem> list = new ArrayList(); 130 131 for (int i=0; i<10; i++) { 132 MediaDescription.Builder bob = new MediaDescription.Builder(); 133 bob.setTitle("Title " + i); 134 bob.setSubtitle("Summary " + i); 135 bob.setMediaId(Uri.withAppendedPath(BASE_URI, 136 Integer.toString(i)).toString()); 137 list.add(new MediaBrowser.MediaItem(bob.build(), 138 MediaBrowser.MediaItem.FLAG_BROWSABLE)); 139 } 140 141 result.sendResult(list); 142 } 143 }, 2000); 144 result.detach(); 145 } 146 147 /* 148 @Override 149 public void query(final Query query, final IMetadataResultHandler metadataResultHandler, 150 final IErrorHandler errorHandler) 151 throws RemoteException { 152 Log.d(TAG, "query: " + query); 153 Utils.checkNotNull(query); 154 Utils.checkNotNull(metadataResultHandler); 155 Utils.checkNotNull(errorHandler); 156 157 // Handle async response 158 new Thread(new Runnable() { 159 public void run() { 160 try { 161 // Pre-load the list of music 162 List<MusicTrack> musicTracks = getMusicList(); 163 if (musicTracks == null) { 164 notifyListenersOnPlaybackStateUpdate(getCurrentPlaybackState()); 165 errorHandler.onError(new Error(Error.UNKNOWN, 166 getString(R.string.music_error))); 167 return; 168 } 169 170 final Uri uri = query.getUri(); 171 int match = sUriMatcher.match(uri); 172 Log.d(TAG, "Queried: " + uri + "; match: " + match); 173 switch (match) { 174 case BROWSE_ROOT: 175 { 176 Log.d(TAG, "Browse_root"); 177 178 try { 179 MatrixCursor matrixCursor = mMusicProvider 180 .getRootContainerCurser(); 181 DataHolder holder = new DataHolder(MEDIA_CONTAINER_PROJECTION, 182 matrixCursor, null); 183 184 Log.d(TAG, "on metadata response called " + holder.getCount()); 185 metadataResultHandler.onMetadataResponse(holder); 186 } catch (RemoteException e) { 187 Log.w(TAG, "Error delivering metadata in the callback.", e); 188 } 189 break; 190 } 191 case NOW_PLAYING: 192 { 193 try { 194 Log.d(TAG, "query NOW_PLAYING"); 195 MatrixCursor matrixCursor = mMusicProvider 196 .getRootItemCursor( 197 PIANO); 198 DataHolder holder = new DataHolder(MEDIA_CONTAINER_PROJECTION, 199 matrixCursor, null); 200 Log.d(TAG, "on metadata response called " + holder.getCount()); 201 metadataResultHandler.onMetadataResponse(holder); 202 } catch (RemoteException e) { 203 Log.w(TAG, "Error querying NOW_PLAYING"); 204 } 205 break; 206 } 207 case PIANO: 208 { 209 try { 210 Log.d(TAG, "query PIANO"); 211 MatrixCursor matrixCursor = mMusicProvider 212 .getRootItemCursor( 213 PIANO); 214 DataHolder holder = new DataHolder(MEDIA_CONTAINER_PROJECTION, 215 matrixCursor, null); 216 Log.d(TAG, "on metadata response called " + holder.getCount()); 217 metadataResultHandler.onMetadataResponse(holder); 218 } catch (RemoteException e) { 219 Log.w(TAG, "Error querying PIANO"); 220 } 221 break; 222 } 223 case VOICE: 224 { 225 try { 226 Log.d(TAG, "query VOICE"); 227 MatrixCursor matrixCursor = mMusicProvider 228 .getRootItemCursor( 229 VOICE); 230 DataHolder holder = new DataHolder(MEDIA_CONTAINER_PROJECTION, 231 matrixCursor, null); 232 Log.d(TAG, "on metadata response called " + holder.getCount()); 233 metadataResultHandler.onMetadataResponse(holder); 234 } catch (RemoteException e) { 235 Log.w(TAG, "Error querying VOICE"); 236 } 237 break; 238 } 239 default: 240 { 241 Log.w(TAG, "Skipping unmatched URI: " + uri); 242 } 243 } 244 } catch (NotFoundException e) { 245 Log.e(TAG, "::run:", e); 246 } catch (RemoteException e) { 247 Log.e(TAG, "::run:", e); 248 } 249 } // end run 250 }).start(); 251 } 252 253 */ 254 } 255