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 package android.car.usb.handler; 17 18 import static android.content.Intent.ACTION_USER_SWITCHED; 19 20 import android.app.ActivityManager; 21 import android.app.Notification; 22 import android.app.NotificationChannel; 23 import android.app.NotificationManager; 24 import android.app.Service; 25 import android.content.BroadcastReceiver; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.hardware.usb.UsbDevice; 30 import android.hardware.usb.UsbManager; 31 import android.os.Binder; 32 import android.os.UserHandle; 33 import android.util.Log; 34 35 import java.util.ArrayList; 36 37 /** 38 * Starts the {@link UsbHostManagementActivity} for each connected usb device when {@link 39 * #onStartCommand(Intent, int, int)} is called. This is meant to allow this activity to start for 40 * connected devices on start up, without holding up processing of the LOCKED_BOOT_COMPLETED intent. 41 */ 42 public class BootUsbService extends Service { 43 private static final String TAG = BootUsbService.class.getSimpleName(); 44 private static final int NOTIFICATION_ID = 1; 45 46 static final String USB_DEVICE_LIST_KEY = "usb_device_list"; 47 48 private ArrayList<UsbDevice> mDeviceList; 49 50 private class UserSwitchBroadcastReceiver extends BroadcastReceiver { 51 @Override onReceive(Context context, Intent intent)52 public void onReceive(Context context, Intent intent) { 53 processDevices(); 54 unregisterReceiver(this); 55 } 56 } 57 58 @Override onBind(Intent intent)59 public Binder onBind(Intent intent) { 60 return null; 61 } 62 63 @Override onCreate()64 public void onCreate() { 65 String notificationIdString = 66 getResources().getString(R.string.usb_boot_service_notification); 67 NotificationManager notificationManager = getSystemService(NotificationManager.class); 68 NotificationChannel notificationChannel = 69 new NotificationChannel( 70 notificationIdString, 71 "Car Usb Handler enumeration", 72 NotificationManager.IMPORTANCE_NONE); 73 notificationManager.createNotificationChannel(notificationChannel); 74 Notification notification = 75 new Notification.Builder( 76 this, notificationIdString).setSmallIcon(R.drawable.ic_launcher).build(); 77 // CarUsbHandler runs in the background, so startForeground must be explicitly called. 78 startForeground(NOTIFICATION_ID, notification); 79 } 80 81 @Override onStartCommand(Intent intent, int flags, int startId)82 public int onStartCommand(Intent intent, int flags, int startId) { 83 mDeviceList = intent.getParcelableArrayListExtra(USB_DEVICE_LIST_KEY); 84 // If the current user is still the system user, wait until the non system user becomes the 85 // current/foreground user. Otherwise, we can go ahead and start processing the USB devices 86 // immediately. 87 if (ActivityManager.getCurrentUser() == UserHandle.USER_SYSTEM) { 88 Log.d(TAG, "Current user is still the system user, waiting for user switch"); 89 registerReceiver( 90 new UserSwitchBroadcastReceiver(), new IntentFilter(ACTION_USER_SWITCHED)); 91 } else { 92 processDevices(); 93 } 94 95 return START_NOT_STICKY; 96 } 97 processDevices()98 private void processDevices() { 99 Log.d(TAG, "Processing connected USB devices and starting handlers"); 100 for (UsbDevice device : mDeviceList) { 101 handle(this, device); 102 } 103 stopSelf(); 104 } 105 handle(Context context, UsbDevice device)106 private void handle(Context context, UsbDevice device) { 107 Intent manageDevice = new Intent(context, UsbHostManagementActivity.class); 108 manageDevice.setAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); 109 manageDevice.putExtra(UsbManager.EXTRA_DEVICE, device); 110 manageDevice.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 111 context.startActivityAsUser(manageDevice, UserHandle.CURRENT); 112 } 113 } 114