Start MtpDocumentsService as foreground service.

Prevously MtpDocumentsService was started as background service, then it
turns into a foreground service by calling Service#startForeground.

The workflow did not work until this, because now background activity
cannot launch a background service.

The CL starts using NotificationManager#startForegroundService to launch
MtpDocumentsService so that the service can be started as foreground
service directly.

Bug: 34468813
Test: MtpDocumentsProviderTests
Test: manual testing with connecting MTP device to Android
Change-Id: Ic35d3e92f234881846e5d82ed04d6681a83035f7
This commit is contained in:
Daichi Hirono
2017-01-26 14:40:19 +09:00
parent 881ba34ba7
commit d3c6dd1522
4 changed files with 65 additions and 37 deletions

View File

@@ -509,7 +509,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
final DeviceToolkit toolkit =
new DeviceToolkit(mMtpManager, mResolver, mDatabase, device);
mDeviceToolkits.put(deviceId, toolkit);
mIntentSender.sendUpdateNotificationIntent();
mIntentSender.sendUpdateNotificationIntent(device);
try {
mRootScanner.resume().await();
} catch (InterruptedException error) {
@@ -526,7 +526,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
closeDeviceInternal(deviceId);
}
mRootScanner.resume();
mIntentSender.sendUpdateNotificationIntent();
mIntentSender.sendUpdateNotificationIntent(null);
}
MtpDeviceRecord[] getOpenedDeviceRecordsCache() {

View File

@@ -19,13 +19,12 @@ package com.android.mtp;
import android.app.Notification;
import android.app.Service;
import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import java.io.IOException;
import android.service.notification.StatusBarNotification;
import java.util.HashSet;
import java.util.Set;
/**
* Service to manage lifetime of DocumentsProvider's process.
@@ -33,12 +32,10 @@ import java.io.IOException;
* starts to run when the first MTP device is opened, and stops when the last MTP device is closed.
*/
public class MtpDocumentsService extends Service {
static final String ACTION_OPEN_DEVICE = "com.android.mtp.OPEN_DEVICE";
static final String ACTION_CLOSE_DEVICE = "com.android.mtp.CLOSE_DEVICE";
static final String ACTION_UPDATE_NOTIFICATION = "com.android.mtp.UPDATE_NOTIFICATION";
static final String EXTRA_DEVICE = "device";
NotificationManager mNotificationManager;
private NotificationManager mNotificationManager;
@Override
public IBinder onBind(Intent intent) {
@@ -67,39 +64,53 @@ public class MtpDocumentsService extends Service {
*/
private boolean updateForegroundState() {
final MtpDocumentsProvider provider = MtpDocumentsProvider.getInstance();
int notificationId = 0;
Notification notification = null;
// TODO: Hide notification if the device has already been removed.
final Set<Integer> openedNotification = new HashSet<>();
boolean hasForegroundNotification = false;
final StatusBarNotification[] activeNotifications =
mNotificationManager.getActiveNotifications();
for (final MtpDeviceRecord record : provider.getOpenedDeviceRecordsCache()) {
final String title = getResources().getString(
R.string.accessing_notification_title,
record.name);
notificationId = record.deviceId;
notification = new Notification.Builder(this)
.setLocalOnly(true)
.setContentTitle(title)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb)
.setCategory(Notification.CATEGORY_SYSTEM)
.setPriority(Notification.PRIORITY_LOW)
.build();
mNotificationManager.notify(record.deviceId, notification);
openedNotification.add(record.deviceId);
if (!hasForegroundNotification) {
// Mark this service as foreground with the notification so that the process is not
// killed by the system while a MTP device is opened.
startForeground(record.deviceId, createNotification(this, record));
hasForegroundNotification = true;
} else {
// Only one notification can be shown as a foreground notification. We need to show
// the rest as normal notification.
mNotificationManager.notify(record.deviceId, createNotification(this, record));
}
}
if (notification != null) {
startForeground(notificationId, notification);
return true;
} else {
for (final StatusBarNotification notification : activeNotifications) {
if (!openedNotification.contains(notification.getId())) {
mNotificationManager.cancel(notification.getId());
}
}
if (!hasForegroundNotification) {
// There is no opened device.
stopForeground(true /* removeNotification */);
stopSelf();
return false;
}
return true;
}
private static void logErrorMessage(Exception exp) {
if (exp.getMessage() != null) {
Log.e(MtpDocumentsProvider.TAG, exp.getMessage());
} else {
Log.e(MtpDocumentsProvider.TAG, exp.toString());
}
public static Notification createNotification(Context context, MtpDeviceRecord device) {
final String title = context.getResources().getString(
R.string.accessing_notification_title,
device.name);
return new Notification.Builder(context)
.setLocalOnly(true)
.setContentTitle(title)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb)
.setCategory(Notification.CATEGORY_SYSTEM)
.setPriority(Notification.PRIORITY_LOW)
.setFlag(Notification.FLAG_NO_CLEAR, true)
.build();
}
}

View File

@@ -16,6 +16,8 @@
package com.android.mtp;
import android.annotation.Nullable;
import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -30,9 +32,22 @@ class ServiceIntentSender {
mContext = context;
}
void sendUpdateNotificationIntent() {
/**
* Notify the change of opened device set.
* @param record If a new device is opened, pass the device record. If a device is closed, pass
* null.
*/
void sendUpdateNotificationIntent(@Nullable MtpDeviceRecord record) {
final Intent intent = new Intent(MtpDocumentsService.ACTION_UPDATE_NOTIFICATION);
intent.setComponent(new ComponentName(mContext, MtpDocumentsService.class));
mContext.startService(intent);
final NotificationManager manager = mContext.getSystemService(NotificationManager.class);
if (record != null) {
manager.startServiceInForeground(
intent,
record.deviceId,
MtpDocumentsService.createNotification(mContext, record));
} else {
mContext.startService(intent);
}
}
}

View File

@@ -16,11 +16,13 @@
package com.android.mtp;
import android.annotation.Nullable;
class TestServiceIntentSender extends ServiceIntentSender {
TestServiceIntentSender() {
super(null);
}
@Override
void sendUpdateNotificationIntent() {}
void sendUpdateNotificationIntent(@Nullable MtpDeviceRecord record) {}
}