1 /* 2 * Copyright (C) 2019 The Android Open Source Project 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 android.app.stubs; 18 19 import android.app.ForegroundServiceStartNotAllowedException; 20 import android.app.Notification; 21 import android.app.NotificationChannel; 22 import android.app.NotificationManager; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.pm.ServiceInfo; 26 import android.media.session.MediaSession; 27 import android.media.session.PlaybackState; 28 import android.util.Log; 29 30 /** 31 * Foreground Service with media type. 32 */ 33 public class LocalForegroundServiceMedia extends LocalForegroundService { 34 35 private static final String TAG = "LocalForegroundServiceMedia"; 36 private static final String NOTIFICATION_CHANNEL_ID = "cts/" + TAG; 37 public static final String EXTRA_FOREGROUND_SERVICE_TYPE = "ForegroundService.type"; 38 public static final int COMMAND_START_FOREGROUND_WITH_TYPE = 1; 39 public static final int COMMAND_PLAY_MEDIA = 100; 40 public static final int COMMAND_POST_MEDIA_NOTIFICATION = 101; 41 public static final int COMMAND_DEACTIVATE_MEDIA_SESSION = 102; 42 public static final int COMMAND_RELEASE_MEDIA_SESSION = 103; 43 public static final int COMMAND_STOP_MEDIA = 104; 44 public static String ACTION_START_FGSM_RESULT = 45 "android.app.stubs.LocalForegroundServiceMedia.RESULT"; 46 public static String FGSM_NOTIFICATION_ID = 47 "android.app.stubs.LocalForegroundServiceMedia.NOTIFICATION_ID"; 48 private int mNotificationId = 1000; 49 50 private MediaSession mMediaSession = null; 51 52 /** Returns the channel id for this service */ getNotificationChannelId()53 public static String getNotificationChannelId() { 54 return NOTIFICATION_CHANNEL_ID; 55 } 56 57 private static long sAllPlayStateActions = 58 PlaybackState.ACTION_PLAY 59 | PlaybackState.ACTION_PAUSE 60 | PlaybackState.ACTION_PLAY_PAUSE 61 | PlaybackState.ACTION_STOP 62 | PlaybackState.ACTION_SKIP_TO_NEXT 63 | PlaybackState.ACTION_SKIP_TO_PREVIOUS 64 | PlaybackState.ACTION_FAST_FORWARD 65 | PlaybackState.ACTION_REWIND; 66 setPlaybackState(int state, MediaSession mediaSession)67 private void setPlaybackState(int state, MediaSession mediaSession) { 68 PlaybackState playbackState = 69 new PlaybackState.Builder() 70 .setActions(sAllPlayStateActions) 71 .setState(state, 0L, 0.0f) 72 .build(); 73 mediaSession.setPlaybackState(playbackState); 74 } 75 76 @Override onCreate()77 public void onCreate() { 78 super.onCreate(); 79 mMediaSession = new MediaSession(this, TAG); 80 mMediaSession.setCallback( 81 new MediaSession.Callback() { 82 @Override 83 public void onPlay() { 84 Log.d(TAG, "received onPlay"); 85 super.onPlay(); 86 setPlaybackState(PlaybackState.STATE_PLAYING, mMediaSession); 87 } 88 89 @Override 90 public void onPause() { 91 Log.d(TAG, "received onPause"); 92 super.onPause(); 93 setPlaybackState(PlaybackState.STATE_PAUSED, mMediaSession); 94 } 95 96 @Override 97 public void onStop() { 98 Log.d(TAG, "received onStop"); 99 super.onStop(); 100 setPlaybackState(PlaybackState.STATE_PAUSED, mMediaSession); 101 } 102 }); 103 mMediaSession.setActive(true); 104 Log.d( 105 getTag(), 106 "service created: " 107 + this 108 + " in " 109 + android.os.Process.myPid() 110 + "with media session: " 111 + mMediaSession); 112 } 113 114 @Override onDestroy()115 public void onDestroy() { 116 mMediaSession.release(); 117 mMediaSession = null; 118 super.onDestroy(); 119 } 120 121 @Override onStartCommand(Intent intent, int flags, int startId)122 public int onStartCommand(Intent intent, int flags, int startId) { 123 String notificationChannelId = getNotificationChannelId(); 124 NotificationManager notificationManager = getSystemService(NotificationManager.class); 125 notificationManager.createNotificationChannel(new NotificationChannel( 126 notificationChannelId, notificationChannelId, 127 NotificationManager.IMPORTANCE_DEFAULT)); 128 129 Context context = getApplicationContext(); 130 int command = intent.getIntExtra(EXTRA_COMMAND, -1); 131 Intent reply = new Intent(ACTION_START_FGSM_RESULT).setFlags( 132 Intent.FLAG_RECEIVER_FOREGROUND); 133 switch (command) { 134 case COMMAND_START_FOREGROUND_WITH_TYPE: 135 final int type = intent.getIntExtra(EXTRA_FOREGROUND_SERVICE_TYPE, 136 ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST); 137 mNotificationId++; 138 final Notification notification = 139 new Notification.Builder(context, NOTIFICATION_CHANNEL_ID) 140 .setContentTitle(getNotificationTitle(mNotificationId)) 141 .setSmallIcon(R.drawable.black) 142 .setStyle( 143 new Notification.MediaStyle() 144 .setMediaSession(mMediaSession.getSessionToken())) 145 .build(); 146 try { 147 startForeground(mNotificationId, notification, type); 148 reply.putExtra(FGSM_NOTIFICATION_ID, mNotificationId); 149 } catch (ForegroundServiceStartNotAllowedException e) { 150 Log.d(TAG, "startForeground gets an " 151 + " ForegroundServiceStartNotAllowedException", e); 152 } 153 break; 154 case COMMAND_STOP_FOREGROUND_REMOVE_NOTIFICATION: 155 Log.d(TAG, "Stopping foreground removing notification"); 156 stopForeground(true); 157 break; 158 case COMMAND_START_NO_FOREGROUND: 159 Log.d(TAG, "Starting without calling startForeground()"); 160 break; 161 case COMMAND_POST_MEDIA_NOTIFICATION: 162 Log.d(TAG, "Posting media style notification"); 163 final Notification notification1 = 164 new Notification.Builder(context, NOTIFICATION_CHANNEL_ID) 165 .setContentTitle(getNotificationTitle(mNotificationId)) 166 .setSmallIcon(R.drawable.black) 167 .setStyle( 168 new Notification.MediaStyle() 169 .setMediaSession(mMediaSession.getSessionToken())) 170 .build(); 171 notificationManager.notify(mNotificationId++, notification1); 172 break; 173 174 case COMMAND_PLAY_MEDIA: 175 Log.d(TAG, "Setting media session state to playing"); 176 setPlaybackState(PlaybackState.STATE_PLAYING, mMediaSession); 177 break; 178 case COMMAND_STOP_MEDIA: 179 Log.d(TAG, "Setting media session state to stopped"); 180 setPlaybackState(PlaybackState.STATE_STOPPED, mMediaSession); 181 break; 182 case COMMAND_DEACTIVATE_MEDIA_SESSION: 183 Log.d(TAG, "Deactivating media session"); 184 mMediaSession.setActive(false); 185 break; 186 case COMMAND_RELEASE_MEDIA_SESSION: 187 Log.d(TAG, "Release media session"); 188 mMediaSession.release(); 189 break; 190 default: 191 Log.e(TAG, "Unknown command: " + command); 192 } 193 sendBroadcast(reply); 194 return START_NOT_STICKY; 195 } 196 } 197