• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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