| /* |
| * Copyright (C) 2019 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 android.car.usb.handler; |
| |
| import static android.content.Intent.ACTION_USER_SWITCHED; |
| |
| import android.app.ActivityManager; |
| import android.app.Notification; |
| import android.app.NotificationChannel; |
| import android.app.NotificationManager; |
| import android.app.Service; |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.hardware.usb.UsbDevice; |
| import android.hardware.usb.UsbManager; |
| import android.os.Binder; |
| import android.os.UserHandle; |
| import android.util.Log; |
| |
| import java.util.ArrayList; |
| |
| /** |
| * Starts the {@link UsbHostManagementActivity} for each connected usb device when {@link |
| * #onStartCommand(Intent, int, int)} is called. This is meant to allow this activity to start for |
| * connected devices on start up, without holding up processing of the LOCKED_BOOT_COMPLETED intent. |
| */ |
| public class BootUsbService extends Service { |
| private static final String TAG = BootUsbService.class.getSimpleName(); |
| private static final int NOTIFICATION_ID = 1; |
| |
| static final String USB_DEVICE_LIST_KEY = "usb_device_list"; |
| |
| private ArrayList<UsbDevice> mDeviceList; |
| private boolean mReceiverRegistered = false; |
| private final BroadcastReceiver mUserSwitchBroadcastReceiver = new BroadcastReceiver() { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| processDevices(); |
| unregisterUserSwitchReceiver(); |
| } |
| }; |
| |
| @Override |
| public Binder onBind(Intent intent) { |
| return null; |
| } |
| |
| @Override |
| public void onCreate() { |
| String notificationIdString = |
| getResources().getString(R.string.usb_boot_service_notification); |
| NotificationManager notificationManager = getSystemService(NotificationManager.class); |
| NotificationChannel notificationChannel = |
| new NotificationChannel( |
| notificationIdString, |
| "Car Usb Handler enumeration", |
| NotificationManager.IMPORTANCE_NONE); |
| notificationManager.createNotificationChannel(notificationChannel); |
| Notification notification = |
| new Notification.Builder( |
| this, notificationIdString).setSmallIcon(R.drawable.ic_launcher).build(); |
| // CarUsbHandler runs in the background, so startForeground must be explicitly called. |
| startForeground(NOTIFICATION_ID, notification); |
| } |
| |
| @Override |
| public int onStartCommand(Intent intent, int flags, int startId) { |
| mDeviceList = intent.getParcelableArrayListExtra(USB_DEVICE_LIST_KEY); |
| // If the current user is still the system user, wait until the non system user becomes the |
| // current/foreground user. Otherwise, we can go ahead and start processing the USB devices |
| // immediately. |
| if (ActivityManager.getCurrentUser() == UserHandle.USER_SYSTEM) { |
| Log.d(TAG, "Current user is still the system user, waiting for user switch"); |
| registerUserSwitchReceiver(); |
| } else { |
| processDevices(); |
| } |
| |
| return START_NOT_STICKY; |
| } |
| |
| @Override |
| public void onDestroy() { |
| unregisterUserSwitchReceiver(); |
| } |
| |
| private void processDevices() { |
| Log.d(TAG, "Processing connected USB devices and starting handlers"); |
| for (UsbDevice device : mDeviceList) { |
| handle(this, device); |
| } |
| stopSelf(); |
| } |
| |
| private void handle(Context context, UsbDevice device) { |
| Intent manageDevice = new Intent(context, UsbHostManagementActivity.class); |
| manageDevice.setAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); |
| manageDevice.putExtra(UsbManager.EXTRA_DEVICE, device); |
| manageDevice.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); |
| context.startActivityAsUser(manageDevice, UserHandle.CURRENT); |
| } |
| |
| private void registerUserSwitchReceiver() { |
| if (!mReceiverRegistered) { |
| registerReceiver(mUserSwitchBroadcastReceiver, new IntentFilter(ACTION_USER_SWITCHED)); |
| mReceiverRegistered = true; |
| } |
| } |
| |
| private void unregisterUserSwitchReceiver() { |
| if (mReceiverRegistered) { |
| unregisterReceiver(mUserSwitchBroadcastReceiver); |
| mReceiverRegistered = false; |
| } |
| } |
| } |