1 /* 2 * Copyright (C) 2020 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 com.android.car.media.testmediaapp; 18 19 import android.app.Notification; 20 import android.app.NotificationChannel; 21 import android.app.NotificationManager; 22 import android.app.PendingIntent; 23 import android.app.Service; 24 import android.content.Intent; 25 import android.location.Location; 26 import android.location.LocationListener; 27 import android.location.LocationManager; 28 import android.os.Bundle; 29 import android.os.IBinder; 30 import android.widget.Toast; 31 32 import androidx.annotation.Nullable; 33 import androidx.core.app.NotificationCompat; 34 35 import com.android.car.media.testmediaapp.prefs.TmaPrefsActivity; 36 37 /** 38 * Service used to test and demonstrate the access to "foreground" permissions. In particular, this 39 * implementation deals with location access from a headless service. This service is initiated 40 * using {@link Service#startService(Intent)} from the browse service as a respond to a custom 41 * playback command. Subsequent start commands make the service toggle between running and stopping. 42 * 43 * In real applications, this service would be handling background playback, maybe using location 44 * and other sensors to automatically select songs. 45 */ 46 public class TmaForegroundService extends Service { 47 public static final String CHANNEL_ID = "ForegroundServiceChannel"; 48 private LocationManager mLocationManager; 49 50 @Override onCreate()51 public void onCreate() { 52 super.onCreate(); 53 } 54 55 @Override onStartCommand(Intent intent, int flags, int startId)56 public int onStartCommand(Intent intent, int flags, int startId) { 57 if (doWork()) { 58 createNotificationChannel(); 59 Intent notificationIntent = new Intent(this, TmaPrefsActivity.class); 60 PendingIntent pendingIntent = PendingIntent.getActivity(this, 61 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE); 62 Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID) 63 .setContentTitle("Foreground Service") 64 .setSmallIcon(R.drawable.ic_app_icon) 65 .setContentIntent(pendingIntent) 66 .build(); 67 startForeground(1, notification); 68 } else { 69 getMainExecutor().execute(this::stopSelf); 70 } 71 72 return START_NOT_STICKY; 73 } 74 75 @Override onDestroy()76 public void onDestroy() { 77 if (mLocationManager != null) { 78 mLocationManager.removeUpdates(mLocationListener); 79 toast("Location is off"); 80 } 81 super.onDestroy(); 82 } 83 84 @Nullable 85 @Override onBind(Intent intent)86 public IBinder onBind(Intent intent) { 87 return null; 88 } 89 createNotificationChannel()90 private void createNotificationChannel() { 91 NotificationChannel serviceChannel = new NotificationChannel( 92 CHANNEL_ID, 93 "Foreground Service Channel", 94 NotificationManager.IMPORTANCE_DEFAULT 95 ); 96 NotificationManager manager = getSystemService(NotificationManager.class); 97 manager.createNotificationChannel(serviceChannel); 98 } 99 doWork()100 private boolean doWork() { 101 if (mLocationManager != null) { 102 return false; 103 } 104 mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE); 105 try { 106 mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 107 0, mLocationListener); 108 toast("Location is on"); 109 } catch (Throwable e) { 110 toast("Unable to get location: " + e.getMessage()); 111 } 112 return true; 113 } 114 115 /** 116 * We use toasts here as it is the only way for a headless service to show something on the 117 * screen. Real application shouldn't be using toasts from service. 118 */ toast(String message)119 private void toast(String message) { 120 Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); 121 } 122 123 private final LocationListener mLocationListener = new LocationListener() { 124 @Override 125 public void onLocationChanged(Location location) { 126 toast("Location provider: " + location.getLatitude() + ":" + location.getLongitude()); 127 } 128 129 @Override 130 public void onStatusChanged(String provider, int status, Bundle extras) { 131 toast("Location provider: " + provider + " status changed to: " + status); 132 } 133 134 @Override 135 public void onProviderEnabled(String provider) { 136 toast("Location provider enabled: " + provider); 137 } 138 139 @Override 140 public void onProviderDisabled(String provider) { 141 toast("Location provider disabled: " + provider); 142 } 143 }; 144 } 145