Home | History | Annotate | Download | only in usb
      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 
     17 package com.android.systemui.usb;
     18 
     19 import com.android.internal.R;
     20 import android.app.Activity;
     21 import android.app.ActivityManager;
     22 import android.app.AlertDialog;
     23 import android.app.Dialog;
     24 import android.content.BroadcastReceiver;
     25 import android.content.Context;
     26 import android.content.DialogInterface;
     27 import android.content.Intent;
     28 import android.content.IntentFilter;
     29 import android.content.DialogInterface.OnCancelListener;
     30 import android.content.pm.ApplicationInfo;
     31 import android.content.pm.PackageManager;
     32 import android.content.pm.PackageManager.NameNotFoundException;
     33 import android.hardware.usb.UsbManager;
     34 import android.os.Bundle;
     35 import android.os.Environment;
     36 import android.os.Handler;
     37 import android.os.HandlerThread;
     38 import android.os.IBinder;
     39 import android.os.storage.IMountService;
     40 import android.os.storage.StorageManager;
     41 import android.os.storage.StorageEventListener;
     42 import android.os.RemoteException;
     43 import android.os.ServiceManager;
     44 import android.widget.ImageView;
     45 import android.widget.Button;
     46 import android.widget.ProgressBar;
     47 import android.widget.TextView;
     48 import android.view.View;
     49 import android.view.Window;
     50 import android.view.WindowManager;
     51 import android.util.Log;
     52 
     53 import 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  */
     60 public 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(UsbManager.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         getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
    118         if (Environment.isExternalStorageRemovable()) {
    119             getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
    120         }
    121 
    122         setContentView(com.android.internal.R.layout.usb_storage_activity);
    123 
    124         mIcon = (ImageView) findViewById(com.android.internal.R.id.icon);
    125         mBanner = (TextView) findViewById(com.android.internal.R.id.banner);
    126         mMessage = (TextView) findViewById(com.android.internal.R.id.message);
    127 
    128         mMountButton = (Button) findViewById(com.android.internal.R.id.mount_button);
    129         mMountButton.setOnClickListener(this);
    130         mUnmountButton = (Button) findViewById(com.android.internal.R.id.unmount_button);
    131         mUnmountButton.setOnClickListener(this);
    132         mProgressBar = (ProgressBar) findViewById(com.android.internal.R.id.progress);
    133     }
    134 
    135     @Override
    136     protected void onDestroy() {
    137         super.onDestroy();
    138         mDestroyed = true;
    139     }
    140 
    141     private void switchDisplay(final boolean usbStorageInUse) {
    142         mUIHandler.post(new Runnable() {
    143             @Override
    144             public void run() {
    145                 switchDisplayAsync(usbStorageInUse);
    146             }
    147         });
    148     }
    149 
    150     private void switchDisplayAsync(boolean usbStorageInUse) {
    151         if (usbStorageInUse) {
    152             mProgressBar.setVisibility(View.GONE);
    153             mUnmountButton.setVisibility(View.VISIBLE);
    154             mMountButton.setVisibility(View.GONE);
    155             mIcon.setImageResource(com.android.internal.R.drawable.usb_android_connected);
    156             mBanner.setText(com.android.internal.R.string.usb_storage_stop_title);
    157             mMessage.setText(com.android.internal.R.string.usb_storage_stop_message);
    158         } else {
    159             mProgressBar.setVisibility(View.GONE);
    160             mUnmountButton.setVisibility(View.GONE);
    161             mMountButton.setVisibility(View.VISIBLE);
    162             mIcon.setImageResource(com.android.internal.R.drawable.usb_android);
    163             mBanner.setText(com.android.internal.R.string.usb_storage_title);
    164             mMessage.setText(com.android.internal.R.string.usb_storage_message);
    165         }
    166     }
    167 
    168     @Override
    169     protected void onResume() {
    170         super.onResume();
    171 
    172         mStorageManager.registerListener(mStorageListener);
    173         registerReceiver(mUsbStateReceiver, new IntentFilter(UsbManager.ACTION_USB_STATE));
    174         try {
    175             mAsyncStorageHandler.post(new Runnable() {
    176                 @Override
    177                 public void run() {
    178                     switchDisplay(mStorageManager.isUsbMassStorageEnabled());
    179                 }
    180             });
    181         } catch (Exception ex) {
    182             Log.e(TAG, "Failed to read UMS enable state", ex);
    183         }
    184     }
    185 
    186     @Override
    187     protected void onPause() {
    188         super.onPause();
    189 
    190         unregisterReceiver(mUsbStateReceiver);
    191         if (mStorageManager == null && mStorageListener != null) {
    192             mStorageManager.unregisterListener(mStorageListener);
    193         }
    194     }
    195 
    196     private void handleUsbStateChanged(Intent intent) {
    197         boolean connected = intent.getExtras().getBoolean(UsbManager.USB_CONNECTED);
    198         if (!connected) {
    199             // It was disconnected from the plug, so finish
    200             finish();
    201         }
    202     }
    203 
    204     private IMountService getMountService() {
    205         IBinder service = ServiceManager.getService("mount");
    206         if (service != null) {
    207             return IMountService.Stub.asInterface(service);
    208         }
    209         return null;
    210     }
    211 
    212     @Override
    213     public Dialog onCreateDialog(int id, Bundle args) {
    214         switch (id) {
    215         case DLG_CONFIRM_KILL_STORAGE_USERS:
    216             return new AlertDialog.Builder(this)
    217                     .setTitle(R.string.dlg_confirm_kill_storage_users_title)
    218                     .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
    219                         public void onClick(DialogInterface dialog, int which) {
    220                             switchUsbMassStorage(true);
    221                         }})
    222                     .setNegativeButton(R.string.cancel, null)
    223                     .setMessage(R.string.dlg_confirm_kill_storage_users_text)
    224                     .setOnCancelListener(this)
    225                     .create();
    226         case DLG_ERROR_SHARING:
    227             return new AlertDialog.Builder(this)
    228                     .setTitle(R.string.dlg_error_title)
    229                     .setNeutralButton(R.string.dlg_ok, null)
    230                     .setMessage(R.string.usb_storage_error_message)
    231                     .setOnCancelListener(this)
    232                     .create();
    233         }
    234         return null;
    235     }
    236 
    237     private void scheduleShowDialog(final int id) {
    238         mUIHandler.post(new Runnable() {
    239             @Override
    240             public void run() {
    241                 if (!mDestroyed) {
    242                     removeDialog(id);
    243                     showDialog(id);
    244                 }
    245             }
    246         });
    247     }
    248 
    249     private void switchUsbMassStorage(final boolean on) {
    250         // things to do on the UI thread
    251         mUIHandler.post(new Runnable() {
    252             @Override
    253             public void run() {
    254                 mUnmountButton.setVisibility(View.GONE);
    255                 mMountButton.setVisibility(View.GONE);
    256 
    257                 mProgressBar.setVisibility(View.VISIBLE);
    258                 // will be hidden once USB mass storage kicks in (or fails)
    259             }
    260         });
    261 
    262         // things to do elsewhere
    263         mAsyncStorageHandler.post(new Runnable() {
    264             @Override
    265             public void run() {
    266                 if (on) {
    267                     mStorageManager.enableUsbMassStorage();
    268                 } else {
    269                     mStorageManager.disableUsbMassStorage();
    270                 }
    271             }
    272         });
    273     }
    274 
    275     private void checkStorageUsers() {
    276         mAsyncStorageHandler.post(new Runnable() {
    277             @Override
    278             public void run() {
    279                 checkStorageUsersAsync();
    280             }
    281         });
    282     }
    283 
    284     private void checkStorageUsersAsync() {
    285         IMountService ims = getMountService();
    286         if (ims == null) {
    287             // Display error dialog
    288             scheduleShowDialog(DLG_ERROR_SHARING);
    289         }
    290         String extStoragePath = Environment.getExternalStorageDirectory().toString();
    291         boolean showDialog = false;
    292         try {
    293             int[] stUsers = ims.getStorageUsers(extStoragePath);
    294             if (stUsers != null && stUsers.length > 0) {
    295                 showDialog = true;
    296             } else {
    297                 // List of applications on sdcard.
    298                 ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
    299                 List<ApplicationInfo> infoList = am.getRunningExternalApplications();
    300                 if (infoList != null && infoList.size() > 0) {
    301                     showDialog = true;
    302                 }
    303             }
    304         } catch (RemoteException e) {
    305             // Display error dialog
    306             scheduleShowDialog(DLG_ERROR_SHARING);
    307         }
    308         if (showDialog) {
    309             // Display dialog to user
    310             scheduleShowDialog(DLG_CONFIRM_KILL_STORAGE_USERS);
    311         } else {
    312             if (localLOGV) Log.i(TAG, "Enabling UMS");
    313             switchUsbMassStorage(true);
    314         }
    315     }
    316 
    317     public void onClick(View v) {
    318         if (v == mMountButton) {
    319            // Check for list of storage users and display dialog if needed.
    320             checkStorageUsers();
    321         } else if (v == mUnmountButton) {
    322             if (localLOGV) Log.i(TAG, "Disabling UMS");
    323             switchUsbMassStorage(false);
    324         }
    325     }
    326 
    327     public void onCancel(DialogInterface dialog) {
    328         finish();
    329     }
    330 
    331 }
    332