UsbStorageActivity.java revision c7f8b6fcf56aeb457013832555f6358f6babee90
1/* 2 * Copyright (C) 2007 Google Inc. 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 17package com.android.systemui.usb; 18 19import com.android.internal.R; 20import android.app.Activity; 21import android.app.ActivityManager; 22import android.app.AlertDialog; 23import android.app.Dialog; 24import android.content.BroadcastReceiver; 25import android.content.Context; 26import android.content.DialogInterface; 27import android.content.Intent; 28import android.content.IntentFilter; 29import android.content.DialogInterface.OnCancelListener; 30import android.content.pm.ApplicationInfo; 31import android.content.pm.PackageManager; 32import android.content.pm.PackageManager.NameNotFoundException; 33import android.hardware.Usb; 34import android.os.Bundle; 35import android.os.Environment; 36import android.os.Handler; 37import android.os.HandlerThread; 38import android.os.IBinder; 39import android.os.storage.IMountService; 40import android.os.storage.StorageManager; 41import android.os.storage.StorageEventListener; 42import android.os.RemoteException; 43import android.os.ServiceManager; 44import android.widget.ImageView; 45import android.widget.Button; 46import android.widget.ProgressBar; 47import android.widget.TextView; 48import android.view.View; 49import android.view.Window; 50import android.view.WindowManager; 51import android.util.Log; 52 53import java.util.List; 54 55/** 56 * This activity is shown to the user for him/her to enable USB mass storage 57 * on-demand (that is, when the USB cable is connected). It uses the alert 58 * dialog style. It will be launched from a notification. 59 */ 60public class UsbStorageActivity extends Activity 61 implements View.OnClickListener, OnCancelListener { 62 private static final String TAG = "UsbStorageActivity"; 63 64 private Button mMountButton; 65 private Button mUnmountButton; 66 private ProgressBar mProgressBar; 67 private TextView mBanner; 68 private TextView mMessage; 69 private ImageView mIcon; 70 private StorageManager mStorageManager = null; 71 private static final int DLG_CONFIRM_KILL_STORAGE_USERS = 1; 72 private static final int DLG_ERROR_SHARING = 2; 73 static final boolean localLOGV = false; 74 private boolean mDestroyed; 75 76 // UI thread 77 private Handler mUIHandler; 78 79 // thread for working with the storage services, which can be slow 80 private Handler mAsyncStorageHandler; 81 82 /** Used to detect when the USB cable is unplugged, so we can call finish() */ 83 private BroadcastReceiver mUsbStateReceiver = new BroadcastReceiver() { 84 @Override 85 public void onReceive(Context context, Intent intent) { 86 if (intent.getAction().equals(Usb.ACTION_USB_STATE)) { 87 handleUsbStateChanged(intent); 88 } 89 } 90 }; 91 92 private StorageEventListener mStorageListener = new StorageEventListener() { 93 @Override 94 public void onStorageStateChanged(String path, String oldState, String newState) { 95 final boolean on = newState.equals(Environment.MEDIA_SHARED); 96 switchDisplay(on); 97 } 98 }; 99 100 @Override 101 protected void onCreate(Bundle savedInstanceState) { 102 super.onCreate(savedInstanceState); 103 104 if (mStorageManager == null) { 105 mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE); 106 if (mStorageManager == null) { 107 Log.w(TAG, "Failed to get StorageManager"); 108 } 109 } 110 111 mUIHandler = new Handler(); 112 113 HandlerThread thr = new HandlerThread("SystemUI UsbStorageActivity"); 114 thr.start(); 115 mAsyncStorageHandler = new Handler(thr.getLooper()); 116 117 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); 118 setProgressBarIndeterminateVisibility(true); 119 120 getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); 121 if (Environment.isExternalStorageRemovable()) { 122 getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); 123 } 124 125 setTitle(getString(com.android.internal.R.string.usb_storage_activity_title)); 126 127 setContentView(com.android.internal.R.layout.usb_storage_activity); 128 129 mIcon = (ImageView) findViewById(com.android.internal.R.id.icon); 130 mBanner = (TextView) findViewById(com.android.internal.R.id.banner); 131 mMessage = (TextView) findViewById(com.android.internal.R.id.message); 132 133 mMountButton = (Button) findViewById(com.android.internal.R.id.mount_button); 134 mMountButton.setOnClickListener(this); 135 mUnmountButton = (Button) findViewById(com.android.internal.R.id.unmount_button); 136 mUnmountButton.setOnClickListener(this); 137 mProgressBar = (ProgressBar) findViewById(com.android.internal.R.id.progress); 138 } 139 140 @Override 141 protected void onDestroy() { 142 super.onDestroy(); 143 mDestroyed = true; 144 } 145 146 private void switchDisplay(final boolean usbStorageInUse) { 147 mUIHandler.post(new Runnable() { 148 @Override 149 public void run() { 150 switchDisplayAsync(usbStorageInUse); 151 } 152 }); 153 } 154 155 private void switchDisplayAsync(boolean usbStorageInUse) { 156 if (usbStorageInUse) { 157 mProgressBar.setVisibility(View.GONE); 158 mUnmountButton.setVisibility(View.VISIBLE); 159 mMountButton.setVisibility(View.GONE); 160 mIcon.setImageResource(com.android.internal.R.drawable.usb_android_connected); 161 mBanner.setText(com.android.internal.R.string.usb_storage_stop_title); 162 mMessage.setText(com.android.internal.R.string.usb_storage_stop_message); 163 } else { 164 mProgressBar.setVisibility(View.GONE); 165 mUnmountButton.setVisibility(View.GONE); 166 mMountButton.setVisibility(View.VISIBLE); 167 mIcon.setImageResource(com.android.internal.R.drawable.usb_android); 168 mBanner.setText(com.android.internal.R.string.usb_storage_title); 169 mMessage.setText(com.android.internal.R.string.usb_storage_message); 170 } 171 } 172 173 @Override 174 protected void onResume() { 175 super.onResume(); 176 177 mStorageManager.registerListener(mStorageListener); 178 registerReceiver(mUsbStateReceiver, new IntentFilter(Usb.ACTION_USB_STATE)); 179 try { 180 mAsyncStorageHandler.post(new Runnable() { 181 @Override 182 public void run() { 183 switchDisplay(mStorageManager.isUsbMassStorageEnabled()); 184 } 185 }); 186 } catch (Exception ex) { 187 Log.e(TAG, "Failed to read UMS enable state", ex); 188 } 189 } 190 191 @Override 192 protected void onPause() { 193 super.onPause(); 194 195 unregisterReceiver(mUsbStateReceiver); 196 if (mStorageManager == null && mStorageListener != null) { 197 mStorageManager.unregisterListener(mStorageListener); 198 } 199 } 200 201 private void handleUsbStateChanged(Intent intent) { 202 boolean connected = intent.getExtras().getBoolean(Usb.USB_CONNECTED); 203 if (!connected) { 204 // It was disconnected from the plug, so finish 205 finish(); 206 } 207 } 208 209 private IMountService getMountService() { 210 IBinder service = ServiceManager.getService("mount"); 211 if (service != null) { 212 return IMountService.Stub.asInterface(service); 213 } 214 return null; 215 } 216 217 @Override 218 public Dialog onCreateDialog(int id, Bundle args) { 219 switch (id) { 220 case DLG_CONFIRM_KILL_STORAGE_USERS: 221 return new AlertDialog.Builder(this) 222 .setTitle(R.string.dlg_confirm_kill_storage_users_title) 223 .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() { 224 public void onClick(DialogInterface dialog, int which) { 225 switchUsbMassStorage(true); 226 }}) 227 .setNegativeButton(R.string.cancel, null) 228 .setMessage(R.string.dlg_confirm_kill_storage_users_text) 229 .setOnCancelListener(this) 230 .create(); 231 case DLG_ERROR_SHARING: 232 return new AlertDialog.Builder(this) 233 .setTitle(R.string.dlg_error_title) 234 .setNeutralButton(R.string.dlg_ok, null) 235 .setMessage(R.string.usb_storage_error_message) 236 .setOnCancelListener(this) 237 .create(); 238 } 239 return null; 240 } 241 242 private void scheduleShowDialog(final int id) { 243 mUIHandler.post(new Runnable() { 244 @Override 245 public void run() { 246 if (!mDestroyed) { 247 removeDialog(id); 248 showDialog(id); 249 } 250 } 251 }); 252 } 253 254 private void switchUsbMassStorage(final boolean on) { 255 // things to do on the UI thread 256 mUIHandler.post(new Runnable() { 257 @Override 258 public void run() { 259 mUnmountButton.setVisibility(View.GONE); 260 mMountButton.setVisibility(View.GONE); 261 262 mProgressBar.setVisibility(View.VISIBLE); 263 // will be hidden once USB mass storage kicks in (or fails) 264 } 265 }); 266 267 // things to do elsewhere 268 mAsyncStorageHandler.post(new Runnable() { 269 @Override 270 public void run() { 271 if (on) { 272 mStorageManager.enableUsbMassStorage(); 273 } else { 274 mStorageManager.disableUsbMassStorage(); 275 } 276 } 277 }); 278 } 279 280 private void checkStorageUsers() { 281 mAsyncStorageHandler.post(new Runnable() { 282 @Override 283 public void run() { 284 checkStorageUsersAsync(); 285 } 286 }); 287 } 288 289 private void checkStorageUsersAsync() { 290 IMountService ims = getMountService(); 291 if (ims == null) { 292 // Display error dialog 293 scheduleShowDialog(DLG_ERROR_SHARING); 294 } 295 String extStoragePath = Environment.getExternalStorageDirectory().toString(); 296 boolean showDialog = false; 297 try { 298 int[] stUsers = ims.getStorageUsers(extStoragePath); 299 if (stUsers != null && stUsers.length > 0) { 300 showDialog = true; 301 } else { 302 // List of applications on sdcard. 303 ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); 304 List<ApplicationInfo> infoList = am.getRunningExternalApplications(); 305 if (infoList != null && infoList.size() > 0) { 306 showDialog = true; 307 } 308 } 309 } catch (RemoteException e) { 310 // Display error dialog 311 scheduleShowDialog(DLG_ERROR_SHARING); 312 } 313 if (showDialog) { 314 // Display dialog to user 315 scheduleShowDialog(DLG_CONFIRM_KILL_STORAGE_USERS); 316 } else { 317 if (localLOGV) Log.i(TAG, "Enabling UMS"); 318 switchUsbMassStorage(true); 319 } 320 } 321 322 public void onClick(View v) { 323 if (v == mMountButton) { 324 // Check for list of storage users and display dialog if needed. 325 checkStorageUsers(); 326 } else if (v == mUnmountButton) { 327 if (localLOGV) Log.i(TAG, "Disabling UMS"); 328 switchUsbMassStorage(false); 329 } 330 } 331 332 public void onCancel(DialogInterface dialog) { 333 finish(); 334 } 335 336} 337