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 {
sUriMatcher.addURI(AUTHORITY, BROWSE_ROOT_BASE_PATH, BROWSE_ROOT)86         sUriMatcher.addURI(AUTHORITY, BROWSE_ROOT_BASE_PATH, BROWSE_ROOT);
sUriMatcher.addURI(AUTHORITY, NOW_PLAYING_PATH, NOW_PLAYING)87         sUriMatcher.addURI(AUTHORITY, NOW_PLAYING_PATH, NOW_PLAYING);
sUriMatcher.addURI(AUTHORITY, PIANO_BASE_PATH, PIANO)88         sUriMatcher.addURI(AUTHORITY, PIANO_BASE_PATH, PIANO);
sUriMatcher.addURI(AUTHORITY, VOICE_BASE_PATH, VOICE)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
onCreate()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
onDestroy()115     public void onDestroy() {
116         super.onDestroy();
117     }
118 
119     @Override
onGetRoot(String clientPackageName, int clientUid, Bundle rootHints)120     public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) {
121         return new BrowserRoot(BROWSE_URI.toString(), null);
122     }
123 
124     @Override
onLoadChildren(final String parentId, final Result<List<MediaBrowser.MediaItem>> result)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