Home | History | Annotate | Download | only in storage
      1 /*
      2  * Copyright (C) 2015 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 
     17 package com.android.tv.settings.device.storage;
     18 
     19 import android.app.Activity;
     20 import android.content.BroadcastReceiver;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.content.IntentFilter;
     24 import android.os.Bundle;
     25 import android.os.storage.DiskInfo;
     26 import android.os.storage.StorageEventListener;
     27 import android.os.storage.StorageManager;
     28 import android.os.storage.VolumeInfo;
     29 import android.os.storage.VolumeRecord;
     30 import android.support.annotation.NonNull;
     31 import android.support.annotation.Nullable;
     32 import android.support.v17.leanback.app.GuidedStepFragment;
     33 import android.support.v17.leanback.widget.GuidanceStylist;
     34 import android.support.v17.leanback.widget.GuidedAction;
     35 import android.text.TextUtils;
     36 
     37 import com.android.tv.settings.R;
     38 import com.android.tv.settings.device.StorageResetActivity;
     39 
     40 import java.util.List;
     41 
     42 public class NewStorageActivity extends Activity {
     43 
     44     private static final String TAG = "NewStorageActivity";
     45 
     46     private static final String ACTION_NEW_STORAGE =
     47             "com.android.tv.settings.device.storage.NewStorageActivity.NEW_STORAGE";
     48     private static final String ACTION_MISSING_STORAGE =
     49             "com.android.tv.settings.device.storage.NewStorageActivity.MISSING_STORAGE";
     50 
     51     public static Intent getNewStorageLaunchIntent(Context context, String volumeId,
     52             String diskId) {
     53         final Intent i = new Intent(context, NewStorageActivity.class);
     54         i.setAction(ACTION_NEW_STORAGE);
     55         i.putExtra(VolumeInfo.EXTRA_VOLUME_ID, volumeId);
     56         i.putExtra(DiskInfo.EXTRA_DISK_ID, diskId);
     57         return i;
     58     }
     59 
     60     public static Intent getMissingStorageLaunchIntent(Context context, String fsUuid) {
     61         final Intent i = new Intent(context, NewStorageActivity.class);
     62         i.setAction(ACTION_MISSING_STORAGE);
     63         i.putExtra(VolumeRecord.EXTRA_FS_UUID, fsUuid);
     64         return i;
     65     }
     66 
     67     @Override
     68     protected void onCreate(@Nullable Bundle savedInstanceState) {
     69         super.onCreate(savedInstanceState);
     70 
     71         if (savedInstanceState == null) {
     72             final String action = getIntent().getAction();
     73 
     74             if (TextUtils.equals(action, ACTION_MISSING_STORAGE)) {
     75                 // Launched from a notification, see com.android.systemui.usb.StorageNotification
     76                 final String fsUuid = getIntent().getStringExtra(VolumeRecord.EXTRA_FS_UUID);
     77                 if (TextUtils.isEmpty(fsUuid)) {
     78                     throw new IllegalStateException(
     79                             "NewStorageActivity launched without specifying missing storage");
     80                 }
     81 
     82                 getFragmentManager().beginTransaction()
     83                         .add(android.R.id.content, MissingStorageFragment.newInstance(fsUuid))
     84                         .commit();
     85             } else {
     86                 final String volumeId = getIntent().getStringExtra(VolumeInfo.EXTRA_VOLUME_ID);
     87                 final String diskId = getIntent().getStringExtra(DiskInfo.EXTRA_DISK_ID);
     88                 if (TextUtils.isEmpty(volumeId) && TextUtils.isEmpty(diskId)) {
     89                     throw new IllegalStateException(
     90                             "NewStorageActivity launched without specifying new storage");
     91                 }
     92 
     93                 getFragmentManager().beginTransaction()
     94                         .add(android.R.id.content, NewStorageFragment.newInstance(volumeId, diskId))
     95                         .commit();
     96             }
     97         }
     98     }
     99 
    100     public static class NewStorageFragment extends GuidedStepFragment {
    101 
    102         private static final int ACTION_BROWSE = 1;
    103         private static final int ACTION_FORMAT_AS_PRIVATE = 2;
    104         private static final int ACTION_UNMOUNT = 3;
    105         private static final int ACTION_FORMAT_AS_PUBLIC = 4;
    106 
    107         private String mVolumeId;
    108         private String mDiskId;
    109         private String mDescription;
    110 
    111         private final StorageEventListener mStorageEventListener = new StorageEventListener() {
    112             @Override
    113             public void onDiskDestroyed(DiskInfo disk) {
    114                 checkForUnmount();
    115             }
    116 
    117             @Override
    118             public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
    119                 checkForUnmount();
    120             }
    121         };
    122 
    123         public static NewStorageFragment newInstance(String volumeId, String diskId) {
    124             final Bundle b = new Bundle(1);
    125             b.putString(VolumeInfo.EXTRA_VOLUME_ID, volumeId);
    126             b.putString(DiskInfo.EXTRA_DISK_ID, diskId);
    127             final NewStorageFragment fragment = new NewStorageFragment();
    128             fragment.setArguments(b);
    129             return fragment;
    130         }
    131 
    132         @Override
    133         public void onCreate(Bundle savedInstanceState) {
    134             StorageManager storageManager = getActivity().getSystemService(StorageManager.class);
    135             mVolumeId = getArguments().getString(VolumeInfo.EXTRA_VOLUME_ID);
    136             mDiskId = getArguments().getString(DiskInfo.EXTRA_DISK_ID);
    137             if (TextUtils.isEmpty(mVolumeId) && TextUtils.isEmpty(mDiskId)) {
    138                 throw new IllegalStateException(
    139                         "NewStorageFragment launched without specifying new storage");
    140             }
    141             if (!TextUtils.isEmpty(mVolumeId)) {
    142                 final VolumeInfo info = storageManager.findVolumeById(mVolumeId);
    143                 mDescription = storageManager.getBestVolumeDescription(info);
    144                 mDiskId = info.getDiskId();
    145             } else {
    146                 final DiskInfo info = storageManager.findDiskById(mDiskId);
    147                 mDescription = info.getDescription();
    148             }
    149 
    150             super.onCreate(savedInstanceState);
    151         }
    152 
    153         @Override
    154         public void onStart() {
    155             super.onStart();
    156             checkForUnmount();
    157             getActivity().getSystemService(StorageManager.class)
    158                     .registerListener(mStorageEventListener);
    159         }
    160 
    161         @Override
    162         public void onStop() {
    163             super.onStop();
    164             getActivity().getSystemService(StorageManager.class)
    165                     .unregisterListener(mStorageEventListener);
    166         }
    167 
    168         @Override
    169         public @NonNull GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) {
    170             return new GuidanceStylist.Guidance(
    171                     getString(R.string.storage_new_title),
    172                     mDescription,
    173                     null,
    174                     getActivity().getDrawable(R.drawable.ic_storage_132dp));
    175         }
    176 
    177         @Override
    178         public void onCreateActions(@NonNull List<GuidedAction> actions,
    179                 Bundle savedInstanceState) {
    180             if (TextUtils.isEmpty(mVolumeId)) {
    181                 actions.add(new GuidedAction.Builder(getContext())
    182                         .title(R.string.storage_new_action_format_public)
    183                         .id(ACTION_FORMAT_AS_PUBLIC)
    184                         .build());
    185             } else {
    186                 actions.add(new GuidedAction.Builder(getContext())
    187                         .title(R.string.storage_new_action_browse)
    188                         .id(ACTION_BROWSE)
    189                         .build());
    190             }
    191             actions.add(new GuidedAction.Builder(getContext())
    192                     .title(R.string.storage_new_action_adopt)
    193                     .id(ACTION_FORMAT_AS_PRIVATE)
    194                     .build());
    195             actions.add(new GuidedAction.Builder(getContext())
    196                     .title(R.string.storage_new_action_eject)
    197                     .id(ACTION_UNMOUNT)
    198                     .build());
    199         }
    200 
    201         @Override
    202         public void onGuidedActionClicked(GuidedAction action) {
    203             switch ((int) action.getId()) {
    204                 case ACTION_FORMAT_AS_PUBLIC:
    205                     startActivity(FormatActivity.getFormatAsPublicIntent(getActivity(), mDiskId));
    206                     break;
    207                 case ACTION_BROWSE:
    208                     startActivity(new Intent(getActivity(), StorageResetActivity.class));
    209                     break;
    210                 case ACTION_FORMAT_AS_PRIVATE:
    211                     startActivity(FormatActivity.getFormatAsPrivateIntent(getActivity(), mDiskId));
    212                     break;
    213                 case ACTION_UNMOUNT:
    214                     // If we've mounted a volume, eject it. Otherwise just treat eject as cancel
    215                     if (!TextUtils.isEmpty(mVolumeId)) {
    216                         startActivity(
    217                                 UnmountActivity.getIntent(getActivity(), mVolumeId, mDescription));
    218                     }
    219                     break;
    220             }
    221             getActivity().finish();
    222         }
    223 
    224         private void checkForUnmount() {
    225             if (!isAdded()) {
    226                 return;
    227             }
    228 
    229             final StorageManager storageManager =
    230                     getContext().getSystemService(StorageManager.class);
    231 
    232             if (!TextUtils.isEmpty(mDiskId)) {
    233                 // If the disk disappears, assume we're done
    234                 final List<DiskInfo> diskInfos = storageManager.getDisks();
    235                 boolean found = false;
    236                 for (DiskInfo diskInfo : diskInfos) {
    237                     if (TextUtils.equals(diskInfo.getId(), mDiskId)) {
    238                         found = true;
    239                         break;
    240                     }
    241                 }
    242                 if (!found) {
    243                     getActivity().finish();
    244                 }
    245             } else if (!TextUtils.isEmpty(mVolumeId)) {
    246                 final List<VolumeInfo> volumeInfos = storageManager.getVolumes();
    247                 boolean found = false;
    248                 for (VolumeInfo volumeInfo : volumeInfos) {
    249                     if (TextUtils.equals(volumeInfo.getId(), mVolumeId)) {
    250                         found = true;
    251                         break;
    252                     }
    253                 }
    254                 if (!found) {
    255                     getActivity().finish();
    256                 }
    257             }
    258         }
    259     }
    260 
    261     public static class MissingStorageFragment extends GuidedStepFragment {
    262 
    263         private String mFsUuid;
    264         private String mDescription;
    265 
    266         private final BroadcastReceiver mDiskReceiver = new BroadcastReceiver() {
    267             @Override
    268             public void onReceive(Context context, Intent intent) {
    269                 if (TextUtils.equals(intent.getAction(), VolumeInfo.ACTION_VOLUME_STATE_CHANGED)) {
    270                     checkForRemount();
    271                 }
    272             }
    273         };
    274 
    275         public static MissingStorageFragment newInstance(String fsUuid) {
    276             final MissingStorageFragment fragment = new MissingStorageFragment();
    277             final Bundle b = new Bundle(1);
    278             b.putString(VolumeRecord.EXTRA_FS_UUID, fsUuid);
    279             fragment.setArguments(b);
    280             return fragment;
    281         }
    282 
    283         @Override
    284         public void onCreate(Bundle savedInstanceState) {
    285             StorageManager storageManager = getActivity().getSystemService(StorageManager.class);
    286             mFsUuid = getArguments().getString(VolumeRecord.EXTRA_FS_UUID);
    287             if (TextUtils.isEmpty(mFsUuid)) {
    288                 throw new IllegalStateException(
    289                         "MissingStorageFragment launched without specifying missing storage");
    290             }
    291             final VolumeRecord volumeRecord = storageManager.findRecordByUuid(mFsUuid);
    292             mDescription = volumeRecord.getNickname();
    293 
    294             super.onCreate(savedInstanceState);
    295         }
    296 
    297         @Override
    298         public void onStart() {
    299             super.onStart();
    300             getContext().registerReceiver(mDiskReceiver,
    301                     new IntentFilter(VolumeInfo.ACTION_VOLUME_STATE_CHANGED));
    302             checkForRemount();
    303         }
    304 
    305         @Override
    306         public void onStop() {
    307             super.onStop();
    308             getContext().unregisterReceiver(mDiskReceiver);
    309         }
    310 
    311         @Override
    312         public @NonNull GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) {
    313             return new GuidanceStylist.Guidance(
    314                     getString(R.string.storage_missing_title, mDescription),
    315                     getString(R.string.storage_missing_description),
    316                     null,
    317                     getActivity().getDrawable(R.drawable.ic_error_132dp));
    318         }
    319 
    320         @Override
    321         public void onCreateActions(@NonNull List<GuidedAction> actions,
    322                 Bundle savedInstanceState) {
    323             actions.add(new GuidedAction.Builder(getContext())
    324                     .clickAction(GuidedAction.ACTION_ID_OK)
    325                     .build());
    326         }
    327 
    328         @Override
    329         public void onGuidedActionClicked(GuidedAction action) {
    330             getActivity().finish();
    331         }
    332 
    333         private void checkForRemount() {
    334             if (!isAdded()) {
    335                 return;
    336             }
    337 
    338             final List<VolumeInfo> volumeInfos =
    339                     getContext().getSystemService(StorageManager.class).getVolumes();
    340 
    341             for (final VolumeInfo info : volumeInfos) {
    342                 if (!TextUtils.equals(info.getFsUuid(), mFsUuid)) {
    343                     continue;
    344                 }
    345                 if (info.isMountedReadable()) {
    346                     getActivity().finish();
    347                 }
    348             }
    349         }
    350     }
    351 
    352 }
    353