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 public class UsbHostManagementActivity extends Activity { 57 private static final String TAG = UsbHostManagementActivity.class.getSimpleName(); 58 59 private HandlersAdapter mListAdapter; 60 private ListView mHandlersList; 61 private TextView mHandlerTitle; 62 private LinearLayout mUsbHandlersDialog; 63 private UsbHostController mController; 64 private PackageManager mPackageManager; 65 66 private final ResolveBroadcastReceiver mResolveBroadcastReceiver 67 = new ResolveBroadcastReceiver(); 68 private boolean mReceiverRegistered = false; 69 unregisterResolveBroadcastReceiver()70 private void unregisterResolveBroadcastReceiver() { 71 if (mReceiverRegistered) { 72 unregisterReceiver(mResolveBroadcastReceiver); 73 mReceiverRegistered = false; 74 } 75 } 76 processDevice()77 private void processDevice() { 78 UsbDevice connectedDevice = getDevice(); 79 80 if (connectedDevice != null) { 81 mController.processDevice(connectedDevice); 82 } else { 83 finish(); 84 } 85 } 86 87 private class ResolveBroadcastReceiver extends BroadcastReceiver { onReceive(Context context, Intent intent)88 public void onReceive(Context context, Intent intent) { 89 // We could have been unregistered after receiving the intent but before processing it, 90 // so make sure we are still registered. 91 if (mReceiverRegistered) { 92 unregisterResolveBroadcastReceiver(); 93 processDevice(); 94 } 95 } 96 } 97 98 private final AdapterView.OnItemClickListener mHandlerClickListener = 99 new AdapterView.OnItemClickListener() { 100 @Override 101 public void onItemClick(AdapterView<?> parent, final View view, int position, long id) { 102 UsbDeviceSettings settings = (UsbDeviceSettings) parent.getItemAtPosition(position); 103 settings.setDefaultHandler(true); 104 mController.applyDeviceSettings(settings); 105 } 106 }; 107 108 @Override onCreate(Bundle savedInstanceState)109 public void onCreate(Bundle savedInstanceState) { 110 super.onCreate(savedInstanceState); 111 requestWindowFeature(Window.FEATURE_NO_TITLE); 112 setContentView(R.layout.usb_host); 113 mUsbHandlersDialog = findViewById(R.id.usb_handlers_dialog); 114 mHandlersList = findViewById(R.id.usb_handlers_list); 115 mHandlerTitle = findViewById(R.id.usb_handler_heading); 116 mListAdapter = new HandlersAdapter(this); 117 mHandlersList.setAdapter(mListAdapter); 118 mHandlersList.setOnItemClickListener(mHandlerClickListener); 119 mController = new UsbHostController(this, new UsbCallbacks()); 120 mPackageManager = getPackageManager(); 121 } 122 123 @Override onDestroy()124 public void onDestroy() { 125 super.onDestroy(); 126 mController.release(); 127 } 128 129 @Override onPause()130 public void onPause() { 131 super.onPause(); 132 unregisterResolveBroadcastReceiver(); 133 } 134 135 @Override onResume()136 public void onResume() { 137 super.onResume(); 138 139 UserManager userManager = getSystemService(UserManager.class); 140 if (userManager.isUserUnlocked() || getUserId() == UserHandle.USER_SYSTEM) { 141 processDevice(); 142 } else { 143 mReceiverRegistered = true; 144 registerReceiver(mResolveBroadcastReceiver, new IntentFilter(ACTION_USER_UNLOCKED)); 145 // in case the car was unlocked while the receiver was being registered 146 if (userManager.isUserUnlocked()) { 147 mResolveBroadcastReceiver.onReceive(this, new Intent(ACTION_USER_UNLOCKED)); 148 } 149 } 150 } 151 152 class UsbCallbacks implements UsbHostController.UsbHostControllerCallbacks { 153 private boolean mProcessing = false; 154 155 @Override shutdown()156 public void shutdown() { 157 runOnUiThread(new Runnable() { 158 @Override 159 public void run() { 160 finish(); 161 } 162 }); 163 } 164 165 @Override processingStarted()166 public void processingStarted() { 167 mProcessing = true; 168 runOnUiThread(new Runnable() { 169 @Override 170 public void run() { 171 if (mProcessing && !mListAdapter.isEmpty()) { 172 mUsbHandlersDialog.setVisibility(View.VISIBLE); 173 } 174 } 175 }); 176 } 177 178 @Override titleChanged(final String title)179 public void titleChanged(final String title) { 180 runOnUiThread(() -> mHandlerTitle.setText(title)); 181 } 182 183 @Override optionsUpdated(final List<UsbDeviceSettings> options)184 public void optionsUpdated(final List<UsbDeviceSettings> options) { 185 if (options != null && !options.isEmpty()) { 186 runOnUiThread(new Runnable() { 187 @Override 188 public void run() { 189 if (mProcessing) { 190 mUsbHandlersDialog.setVisibility(View.VISIBLE); 191 } 192 mListAdapter.clear(); 193 mListAdapter.addAll(options); 194 } 195 }); 196 } 197 } 198 } 199 200 @Override onNewIntent(Intent intent)201 public void onNewIntent(Intent intent) { 202 super.onNewIntent(intent); 203 setIntent(intent); 204 } 205 206 @Nullable getDevice()207 private UsbDevice getDevice() { 208 if (!UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(getIntent().getAction())) { 209 return null; 210 } 211 return (UsbDevice) getIntent().getParcelableExtra(UsbManager.EXTRA_DEVICE); 212 } 213 214 private class HandlersAdapter extends ArrayAdapter<UsbDeviceSettings> { 215 class HandlerHolder { 216 public TextView mAppName; 217 public ImageView mAppIcon; 218 } 219 HandlersAdapter(Context context)220 HandlersAdapter(Context context) { 221 super(context, R.layout.usb_handler_row); 222 } 223 224 @Override getView(int position, View convertView, ViewGroup parent)225 public View getView(int position, View convertView, ViewGroup parent) { 226 View rowView = convertView; 227 if (rowView == null) { 228 rowView = getLayoutInflater().inflate(R.layout.usb_handler_row, null); 229 HandlerHolder holder = new HandlerHolder(); 230 holder.mAppName = (TextView) rowView.findViewById(R.id.usb_handler_title); 231 holder.mAppIcon = (ImageView) rowView.findViewById(R.id.usb_handler_icon); 232 rowView.setTag(holder); 233 } 234 235 HandlerHolder holder = (HandlerHolder) rowView.getTag(); 236 ComponentName handler = getItem(position).getHandler(); 237 238 try { 239 ApplicationInfo appInfo = 240 mPackageManager.getApplicationInfo(handler.getPackageName(), 0); 241 holder.mAppName.setText(appInfo.loadLabel(mPackageManager)); 242 holder.mAppIcon.setImageDrawable(appInfo.loadIcon(mPackageManager)); 243 } catch (NameNotFoundException e) { 244 Log.e(TAG, "Handling package not found: " + handler.getPackageName()); 245 holder.mAppName.setText(handler.flattenToShortString()); 246 holder.mAppIcon.setImageResource(android.R.color.transparent); 247 } 248 return rowView; 249 } 250 } 251 } 252