diff options
author | Roberto Perez <robertoalexis@google.com> | 2020-05-19 16:24:45 -0700 |
---|---|---|
committer | Roberto Perez <robertoalexis@google.com> | 2020-05-19 16:24:45 -0700 |
commit | 51feade5d719660667351b662c200d31525ea888 (patch) | |
tree | 96c3567d45b246c8a965645c647d3c3f3c7d239a /TestMediaApp/src | |
parent | 26038d631c5e4a7fa99af86040ba109c1b6b5179 (diff) | |
download | tests-51feade5d719660667351b662c200d31525ea888.tar.gz |
Add foreground service test code
Bug: 153875734
Test: ran on emulator
Change-Id: I24c81107886127edd911e7418a28f4699189f3ec
Diffstat (limited to 'TestMediaApp/src')
4 files changed, 179 insertions, 2 deletions
diff --git a/TestMediaApp/src/com/android/car/media/testmediaapp/TmaForegroundService.java b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaForegroundService.java new file mode 100644 index 0000000..6241455 --- /dev/null +++ b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaForegroundService.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * 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.android.car.media.testmediaapp; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Intent; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.os.Bundle; +import android.os.IBinder; +import android.widget.Toast; + +import androidx.annotation.Nullable; +import androidx.core.app.NotificationCompat; + +import com.android.car.media.testmediaapp.prefs.TmaPrefsActivity; + +/** + * Service used to test and demonstrate the access to "foreground" permissions. In particular, this + * implementation deals with location access from a headless service. This service is initiated + * using {@link Service#startService(Intent)} from the browse service as a respond to a custom + * playback command. Subsequent start commands make the service toggle between running and stopping. + * + * In real applications, this service would be handling background playback, maybe using location + * and other sensors to automatically select songs. + */ +public class TmaForegroundService extends Service { + public static final String CHANNEL_ID = "ForegroundServiceChannel"; + private LocationManager mLocationManager; + + @Override + public void onCreate() { + super.onCreate(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (doWork()) { + createNotificationChannel(); + Intent notificationIntent = new Intent(this, TmaPrefsActivity.class); + PendingIntent pendingIntent = PendingIntent.getActivity(this, + 0, notificationIntent, 0); + Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID) + .setContentTitle("Foreground Service") + .setSmallIcon(R.drawable.ic_app_icon) + .setContentIntent(pendingIntent) + .build(); + startForeground(1, notification); + } else { + getMainExecutor().execute(this::stopSelf); + } + + return START_NOT_STICKY; + } + + @Override + public void onDestroy() { + if (mLocationManager != null) { + mLocationManager.removeUpdates(mLocationListener); + toast("Location is off"); + } + super.onDestroy(); + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } + + private void createNotificationChannel() { + NotificationChannel serviceChannel = new NotificationChannel( + CHANNEL_ID, + "Foreground Service Channel", + NotificationManager.IMPORTANCE_DEFAULT + ); + NotificationManager manager = getSystemService(NotificationManager.class); + manager.createNotificationChannel(serviceChannel); + } + + private boolean doWork() { + if (mLocationManager != null) { + return false; + } + mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE); + try { + mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, + 0, mLocationListener); + toast("Location is on"); + } catch (Throwable e) { + toast("Unable to get location: " + e.getMessage()); + } + return true; + } + + /** + * We use toasts here as it is the only way for a headless service to show something on the + * screen. Real application shouldn't be using toasts from service. + */ + private void toast(String message) { + Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); + } + + private final LocationListener mLocationListener = new LocationListener() { + @Override + public void onLocationChanged(Location location) { + toast("Location provider: " + location.getLatitude() + ":" + location.getLongitude()); + } + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { + toast("Location provider: " + provider + " status changed to: " + status); + } + + @Override + public void onProviderEnabled(String provider) { + toast("Location provider enabled: " + provider); + } + + @Override + public void onProviderDisabled(String provider) { + toast("Location provider disabled: " + provider); + } + }; +} diff --git a/TestMediaApp/src/com/android/car/media/testmediaapp/TmaMediaItem.java b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaMediaItem.java index 129e267..e2cb533 100644 --- a/TestMediaApp/src/com/android/car/media/testmediaapp/TmaMediaItem.java +++ b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaMediaItem.java @@ -55,7 +55,9 @@ public class TmaMediaItem { HEART_PLUS_PLUS(CUSTOM_ACTION_PREFIX + "heart_plus_plus", R.string.heart_plus_plus, R.drawable.ic_heart_plus_plus), HEART_LESS_LESS(CUSTOM_ACTION_PREFIX + "heart_less_less", R.string.heart_less_less, - R.drawable.ic_heart_less_less); + R.drawable.ic_heart_less_less), + REQUEST_LOCATION(CUSTOM_ACTION_PREFIX + "location", R.string.location, + R.drawable.ic_location); final String mId; final int mNameId; diff --git a/TestMediaApp/src/com/android/car/media/testmediaapp/TmaPlayer.java b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaPlayer.java index d8fab6c..65cc787 100644 --- a/TestMediaApp/src/com/android/car/media/testmediaapp/TmaPlayer.java +++ b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaPlayer.java @@ -30,6 +30,7 @@ import static android.support.v4.media.session.PlaybackStateCompat.ERROR_CODE_AP import static android.support.v4.media.session.PlaybackStateCompat.STATE_ERROR; import androidx.annotation.Nullable; + import android.app.PendingIntent; import android.content.Context; import android.content.Intent; @@ -77,7 +78,6 @@ public class TmaPlayer extends MediaSessionCompat.Callback { private TmaMediaItem mActiveItem; private int mNextEventIndex = -1; - TmaPlayer(Context context, TmaLibrary library, AudioManager audioManager, Handler handler, MediaSessionCompat session) { mContext = context; @@ -248,6 +248,8 @@ public class TmaPlayer extends MediaSessionCompat.Callback { } else if (TmaCustomAction.HEART_LESS_LESS.mId.equals(action)) { mActiveItem.mHearts--; toast("" + mActiveItem.mHearts); + } else if (TmaCustomAction.REQUEST_LOCATION.mId.equals(action)) { + mContext.startService(new Intent(mContext, TmaForegroundService.class)); } } } diff --git a/TestMediaApp/src/com/android/car/media/testmediaapp/prefs/TmaPrefsFragment.java b/TestMediaApp/src/com/android/car/media/testmediaapp/prefs/TmaPrefsFragment.java index 066cc9c..d3e681e 100644 --- a/TestMediaApp/src/com/android/car/media/testmediaapp/prefs/TmaPrefsFragment.java +++ b/TestMediaApp/src/com/android/car/media/testmediaapp/prefs/TmaPrefsFragment.java @@ -16,8 +16,12 @@ package com.android.car.media.testmediaapp.prefs; +import android.Manifest; +import android.app.Activity; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Bundle; +import android.widget.Toast; import androidx.preference.DropDownPreference; import androidx.preference.Preference; @@ -30,6 +34,8 @@ import com.android.car.media.testmediaapp.prefs.TmaEnumPrefs.TmaLoginEventOrder; import com.android.car.media.testmediaapp.prefs.TmaEnumPrefs.TmaReplyDelay; import com.android.car.media.testmediaapp.prefs.TmaPrefs.PrefEntry; +import java.util.function.Consumer; + public class TmaPrefsFragment extends PreferenceFragmentCompat { @Override @@ -49,6 +55,8 @@ public class TmaPrefsFragment extends PreferenceFragmentCompat { prefs.mAssetReplyDelay, TmaReplyDelay.values())); screen.addPreference(createEnumPref(context, "Login event order", prefs.mLoginEventOrder, TmaLoginEventOrder.values())); + screen.addPreference(createClickPref(context, "Request location perm", + this::requestPermissions)); setPreferenceScreen(screen); } @@ -72,4 +80,25 @@ public class TmaPrefsFragment extends PreferenceFragmentCompat { prefWidget.setEntryValues(entryValues); return prefWidget; } + + private Preference createClickPref(Context context, String title, Consumer<Context> runnable) { + Preference prefWidget = new Preference(context); + prefWidget.setTitle(title); + prefWidget.setOnPreferenceClickListener(pref -> { + runnable.accept(context); + return true; + }); + return prefWidget; + } + + private void requestPermissions(Context context) { + if (context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) + == PackageManager.PERMISSION_GRANTED) { + Toast.makeText(context, "Location permission already granted", Toast.LENGTH_SHORT) + .show(); + } else { + ((Activity) context).requestPermissions( + new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, 1); + } + } } |