1 /* 2 * Copyright (C) 2016 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_UNLOCKED; 19 20 import android.annotation.Nullable; 21 import android.app.Activity; 22 import android.content.BroadcastReceiver; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.content.pm.ApplicationInfo; 28 import android.content.pm.PackageManager; 29 import android.content.pm.PackageManager.NameNotFoundException; 30 import android.hardware.usb.UsbDevice; 31 import android.hardware.usb.UsbManager; 32 import android.os.Bundle; 33 import android.os.UserHandle; 34 import android.os.UserManager; 35 import android.util.Log; 36 import android.view.View; 37 import android.view.ViewGroup; 38 import android.view.Window; 39 import android.widget.AdapterView; 40 import android.widget.ArrayAdapter; 41 import android.widget.ImageView; 42 import android.widget.LinearLayout; 43 import android.widget.ListView; 44 import android.widget.TextView; 45 46 import java.util.List; 47 48 /** 49 * Activity to handle USB device attached. 50 * <p> 51 * When user plugs in USB device: a) Device was used before and user selected handler for it. In 52 * this case handler will be launched. b) Device has not handler assigned. In this case supported 53 * handlers will be captured, and user will be presented with choice to assign default handler. 54 * After that handler will be launched. 55 * 56 * <p>Note: Activity launched by the system and by {@link BootUsbService}. 57 */ 58 public class UsbHostManagementActivity extends Activity { 59 private static final String TAG = UsbHostManagementActivity.class.getSimpleName(); 60 61 private HandlersAdapter mListAdapter; 62 private ListView mHandlersList; 63 private TextView mHandlerTitle; 64 private LinearLayout mUsbHandlersDialog; 65 private UsbHostController mController; 66 private PackageManager mPackageManager; 67 68 private final ResolveBroadcastReceiver mResolveBroadcastReceiver 69 = new ResolveBroadcastReceiver(); 70 private boolean mReceiverRegistered = false; 71 unregisterResolveBroadcastReceiver()72 private void unregisterResolveBroadcastReceiver() { 73 if (mReceiverRegistered) { 74 Log.d(TAG, "Unregistering USER_UNLOCKED broadcast"); 75 unregisterReceiver(mResolveBroadcastReceiver); 76 mReceiverRegistered = false; 77 } 78 } 79 processDevice()80 private void processDevice() { 81 UsbDevice connectedDevice = getDevice(); 82 83 if (connectedDevice != null) { 84 Log.d(TAG, "Processing device: " + connectedDevice.getProductName()); 85 mController.processDevice(connectedDevice); 86 } else { 87 Log.d(TAG, "Device not found."); 88 finish(); 89 } 90 } 91 92 private class ResolveBroadcastReceiver extends BroadcastReceiver { onReceive(Context context, Intent intent)93 public void onReceive(Context context, Intent intent) { 94 // We could have been unregistered after receiving the intent but before processing it, 95 // so make sure we are still registered. 96 if (mReceiverRegistered) { 97 unregisterResolveBroadcastReceiver(); 98 processDevice(); 99 } 100 } 101 } 102 103 private final AdapterView.OnItemClickListener mHandlerClickListener = 104 new AdapterView.OnItemClickListener() { 105 @Override 106 public void onItemClick(AdapterView<?> parent, final View view, int position, long id) { 107 UsbDeviceSettings settings = (UsbDeviceSettings) parent.getItemAtPosition(position); 108 settings.setDefaultHandler(true); 109 mController.applyDeviceSettings(settings); 110 } 111 }; 112 113 @Override onCreate(Bundle savedInstanceState)114 public void onCreate(Bundle savedInstanceState) { 115 super.onCreate(savedInstanceState); 116 requestWindowFeature(Window.FEATURE_NO_TITLE); 117 setContentView(R.layout.usb_host); 118 mUsbHandlersDialog = findViewById(R.id.usb_handlers_dialog); 119 mHandlersList = findViewById(R.id.usb_handlers_list); 120 mHandlerTitle = findViewById(R.id.usb_handler_heading); 121 mListAdapter = new HandlersAdapter(this); 122 mHandlersList.setAdapter(mListAdapter); 123 mHandlersList.setOnItemClickListener(mHandlerClickListener); 124 mController = new UsbHostController(this, new UsbCallbacks()); 125 mPackageManager = getPackageManager(); 126 hideDialog(); 127 } 128 129 @Override onDestroy()130 public void onDestroy() { 131 super.onDestroy(); 132 mController.release(); 133 } 134 135 @Override onPause()136 public void onPause() { 137 super.onPause(); 138 unregisterResolveBroadcastReceiver(); 139 } 140 141 @Override onResume()142 public void onResume() { 143 super.onResume(); 144 145 UserManager userManager = getSystemService(UserManager.class); 146 // Checks should pass if activity is started from BootUsbService, but necessary for system 147 // calls. 148 if (userManager.isUserUnlocked() || getUserId() == UserHandle.USER_SYSTEM) { 149 processDevice(); 150 } else { 151 Log.d(TAG, "Waiting for user unlocked to process device."); 152 mReceiverRegistered = true; 153 registerReceiver(mResolveBroadcastReceiver, new IntentFilter(ACTION_USER_UNLOCKED), 154 Context.RECEIVER_NOT_EXPORTED); 155 // in case the car was unlocked while the receiver was being registered 156 if (userManager.isUserUnlocked()) { 157 mResolveBroadcastReceiver.onReceive(this, new Intent(ACTION_USER_UNLOCKED)); 158 } 159 } 160 } 161 hideDialog()162 private void hideDialog() { 163 setTheme(android.R.style.Theme_Translucent); 164 if (mUsbHandlersDialog != null) { 165 mUsbHandlersDialog.setVisibility(View.GONE); 166 } 167 } 168 showDialog()169 private void showDialog() { 170 setTranslucent(false); 171 setTheme(android.R.style.Theme_DeviceDefault_Dialog); 172 if (mUsbHandlersDialog != null) { 173 mUsbHandlersDialog.setVisibility(View.VISIBLE); 174 } 175 } 176 177 class UsbCallbacks implements UsbHostController.UsbHostControllerCallbacks { 178 private boolean mProcessing = false; 179 180 @Override shutdown()181 public void shutdown() { 182 runOnUiThread(new Runnable() { 183 @Override 184 public void run() { 185 finish(); 186 } 187 }); 188 } 189 190 @Override processingStarted()191 public void processingStarted() { 192 mProcessing = true; 193 runOnUiThread(new Runnable() { 194 @Override 195 public void run() { 196 if (mProcessing && !mListAdapter.isEmpty()) { 197 showDialog(); 198 } 199 } 200 }); 201 } 202 203 @Override titleChanged(final String title)204 public void titleChanged(final String title) { 205 runOnUiThread(() -> mHandlerTitle.setText(title)); 206 } 207 208 @Override optionsUpdated(final List<UsbDeviceSettings> options)209 public void optionsUpdated(final List<UsbDeviceSettings> options) { 210 if (options != null && !options.isEmpty()) { 211 runOnUiThread(new Runnable() { 212 @Override 213 public void run() { 214 if (mProcessing) { 215 showDialog(); 216 } 217 mListAdapter.clear(); 218 mListAdapter.addAll(options); 219 } 220 }); 221 } 222 } 223 } 224 225 @Override onNewIntent(Intent intent)226 public void onNewIntent(Intent intent) { 227 super.onNewIntent(intent); 228 setIntent(intent); 229 } 230 231 @Nullable getDevice()232 private UsbDevice getDevice() { 233 if (!UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(getIntent().getAction())) { 234 return null; 235 } 236 return (UsbDevice) getIntent().getParcelableExtra(UsbManager.EXTRA_DEVICE); 237 } 238 239 private class HandlersAdapter extends ArrayAdapter<UsbDeviceSettings> { 240 class HandlerHolder { 241 public TextView mAppName; 242 public ImageView mAppIcon; 243 } 244 HandlersAdapter(Context context)245 HandlersAdapter(Context context) { 246 super(context, R.layout.usb_handler_row); 247 } 248 249 @Override getView(int position, View convertView, ViewGroup parent)250 public View getView(int position, View convertView, ViewGroup parent) { 251 View rowView = convertView; 252 if (rowView == null) { 253 rowView = getLayoutInflater().inflate(R.layout.usb_handler_row, null); 254 HandlerHolder holder = new HandlerHolder(); 255 holder.mAppName = (TextView) rowView.findViewById(R.id.usb_handler_title); 256 holder.mAppIcon = (ImageView) rowView.findViewById(R.id.usb_handler_icon); 257 rowView.setTag(holder); 258 } 259 260 HandlerHolder holder = (HandlerHolder) rowView.getTag(); 261 ComponentName handler = getItem(position).getHandler(); 262 263 try { 264 ApplicationInfo appInfo = 265 mPackageManager.getApplicationInfo(handler.getPackageName(), 0); 266 holder.mAppName.setText(appInfo.loadLabel(mPackageManager)); 267 holder.mAppIcon.setImageDrawable(appInfo.loadIcon(mPackageManager)); 268 } catch (NameNotFoundException e) { 269 Log.e(TAG, "Handling package not found: " + handler.getPackageName()); 270 holder.mAppName.setText(handler.flattenToShortString()); 271 holder.mAppIcon.setImageResource(android.R.color.transparent); 272 } 273 return rowView; 274 } 275 } 276 } 277