Home | History | Annotate | Download | only in deviceinfo
      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.settings.deviceinfo;
     18 
     19 import android.app.AlertDialog;
     20 import android.app.Dialog;
     21 import android.app.DialogFragment;
     22 import android.content.Context;
     23 import android.content.DialogInterface;
     24 import android.content.Intent;
     25 import android.content.pm.IPackageMoveObserver;
     26 import android.os.AsyncTask;
     27 import android.os.Bundle;
     28 import android.os.storage.DiskInfo;
     29 import android.os.storage.StorageManager;
     30 import android.os.storage.VolumeInfo;
     31 import android.text.TextUtils;
     32 import android.util.Log;
     33 import android.view.View;
     34 import android.widget.Toast;
     35 
     36 import com.android.settings.R;
     37 
     38 import java.util.Objects;
     39 
     40 import static com.android.settings.deviceinfo.StorageSettings.TAG;
     41 
     42 public class StorageWizardFormatProgress extends StorageWizardBase {
     43     private static final String TAG_SLOW_WARNING = "slow_warning";
     44 
     45     private boolean mFormatPrivate;
     46 
     47     private PartitionTask mTask;
     48 
     49     @Override
     50     protected void onCreate(Bundle savedInstanceState) {
     51         super.onCreate(savedInstanceState);
     52         if (mDisk == null) {
     53             finish();
     54             return;
     55         }
     56         setContentView(R.layout.storage_wizard_progress);
     57         setKeepScreenOn(true);
     58 
     59         mFormatPrivate = getIntent().getBooleanExtra(
     60                 StorageWizardFormatConfirm.EXTRA_FORMAT_PRIVATE, false);
     61         setIllustrationType(
     62                 mFormatPrivate ? ILLUSTRATION_INTERNAL : ILLUSTRATION_PORTABLE);
     63 
     64         setHeaderText(R.string.storage_wizard_format_progress_title, mDisk.getDescription());
     65         setBodyText(R.string.storage_wizard_format_progress_body, mDisk.getDescription());
     66 
     67         getNextButton().setVisibility(View.GONE);
     68 
     69         mTask = (PartitionTask) getLastNonConfigurationInstance();
     70         if (mTask == null) {
     71             mTask = new PartitionTask();
     72             mTask.setActivity(this);
     73             mTask.execute();
     74         } else {
     75             mTask.setActivity(this);
     76         }
     77     }
     78 
     79     @Override
     80     public Object onRetainNonConfigurationInstance() {
     81         return mTask;
     82     }
     83 
     84     public static class PartitionTask extends AsyncTask<Void, Integer, Exception> {
     85         public StorageWizardFormatProgress mActivity;
     86 
     87         private volatile int mProgress = 20;
     88 
     89         private volatile long mInternalBench;
     90         private volatile long mPrivateBench;
     91 
     92         @Override
     93         protected Exception doInBackground(Void... params) {
     94             final StorageWizardFormatProgress activity = mActivity;
     95             final StorageManager storage = mActivity.mStorage;
     96             try {
     97                 if (activity.mFormatPrivate) {
     98                     storage.partitionPrivate(activity.mDisk.getId());
     99                     publishProgress(40);
    100 
    101                     mInternalBench = storage.benchmark(null);
    102                     publishProgress(60);
    103 
    104                     final VolumeInfo privateVol = activity.findFirstVolume(VolumeInfo.TYPE_PRIVATE);
    105                     mPrivateBench = storage.benchmark(privateVol.getId());
    106 
    107                     // If we just adopted the device that had been providing
    108                     // physical storage, then automatically move storage to the
    109                     // new emulated volume.
    110                     if (activity.mDisk.isDefaultPrimary()
    111                             && Objects.equals(storage.getPrimaryStorageUuid(),
    112                                     StorageManager.UUID_PRIMARY_PHYSICAL)) {
    113                         Log.d(TAG, "Just formatted primary physical; silently moving "
    114                                 + "storage to new emulated volume");
    115                         storage.setPrimaryStorageUuid(privateVol.getFsUuid(), new SilentObserver());
    116                     }
    117 
    118                 } else {
    119                     storage.partitionPublic(activity.mDisk.getId());
    120                 }
    121                 return null;
    122             } catch (Exception e) {
    123                 return e;
    124             }
    125         }
    126 
    127         @Override
    128         protected void onProgressUpdate(Integer... progress) {
    129             mProgress = progress[0];
    130             mActivity.setCurrentProgress(mProgress);
    131         }
    132 
    133         public void setActivity(StorageWizardFormatProgress activity) {
    134             mActivity = activity;
    135             mActivity.setCurrentProgress(mProgress);
    136         }
    137 
    138         @Override
    139         protected void onPostExecute(Exception e) {
    140             final StorageWizardFormatProgress activity = mActivity;
    141             if (activity.isDestroyed()) {
    142                 return;
    143             }
    144 
    145             if (e != null) {
    146                 Log.e(TAG, "Failed to partition", e);
    147                 Toast.makeText(activity, e.getMessage(), Toast.LENGTH_LONG).show();
    148                 activity.finishAffinity();
    149                 return;
    150             }
    151 
    152             if (activity.mFormatPrivate) {
    153                 final float pct = (float) mInternalBench / (float) mPrivateBench;
    154                 Log.d(TAG, "New volume is " + pct + "x the speed of internal");
    155 
    156                 // To help set user expectations around device performance, we
    157                 // warn if the adopted media is 0.25x the speed of internal
    158                 // storage or slower.
    159                 if (Float.isNaN(pct) || pct < 0.25) {
    160                     final SlowWarningFragment dialog = new SlowWarningFragment();
    161                     dialog.showAllowingStateLoss(activity.getFragmentManager(), TAG_SLOW_WARNING);
    162                 } else {
    163                     activity.onFormatFinished();
    164                 }
    165             } else {
    166                 activity.onFormatFinished();
    167             }
    168         }
    169     }
    170 
    171     public static class SlowWarningFragment extends DialogFragment {
    172         @Override
    173         public Dialog onCreateDialog(Bundle savedInstanceState) {
    174             final Context context = getActivity();
    175 
    176             final AlertDialog.Builder builder = new AlertDialog.Builder(context);
    177 
    178             final StorageWizardFormatProgress target =
    179                     (StorageWizardFormatProgress) getActivity();
    180             final String descrip = target.getDiskDescription();
    181             final String genericDescip = target.getGenericDiskDescription();
    182             builder.setMessage(TextUtils.expandTemplate(getText(R.string.storage_wizard_slow_body),
    183                     descrip, genericDescip));
    184 
    185             builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
    186                 @Override
    187                 public void onClick(DialogInterface dialog, int which) {
    188                     final StorageWizardFormatProgress target =
    189                             (StorageWizardFormatProgress) getActivity();
    190                     target.onFormatFinished();
    191                 }
    192             });
    193 
    194             return builder.create();
    195         }
    196     }
    197 
    198     private String getDiskDescription() {
    199         return mDisk.getDescription();
    200     }
    201 
    202     private String getGenericDiskDescription() {
    203         // TODO: move this directly to DiskInfo
    204         if (mDisk.isSd()) {
    205             return getString(com.android.internal.R.string.storage_sd_card);
    206         } else if (mDisk.isUsb()) {
    207             return getString(com.android.internal.R.string.storage_usb_drive);
    208         } else {
    209             return null;
    210         }
    211     }
    212 
    213     private void onFormatFinished() {
    214         final String forgetUuid = getIntent().getStringExtra(
    215                 StorageWizardFormatConfirm.EXTRA_FORGET_UUID);
    216         if (!TextUtils.isEmpty(forgetUuid)) {
    217             mStorage.forgetVolume(forgetUuid);
    218         }
    219 
    220         final boolean offerMigrate;
    221         if (mFormatPrivate) {
    222             // Offer to migrate only if storage is currently internal
    223             final VolumeInfo privateVol = getPackageManager()
    224                     .getPrimaryStorageCurrentVolume();
    225             offerMigrate = (privateVol != null
    226                     && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.getId()));
    227         } else {
    228             offerMigrate = false;
    229         }
    230 
    231         if (offerMigrate) {
    232             final Intent intent = new Intent(this, StorageWizardMigrate.class);
    233             intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
    234             startActivity(intent);
    235         } else {
    236             final Intent intent = new Intent(this, StorageWizardReady.class);
    237             intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
    238             startActivity(intent);
    239         }
    240         finishAffinity();
    241     }
    242 
    243     private static class SilentObserver extends IPackageMoveObserver.Stub {
    244         @Override
    245         public void onCreated(int moveId, Bundle extras) {
    246             // Ignored
    247         }
    248 
    249         @Override
    250         public void onStatusChanged(int moveId, int status, long estMillis) {
    251             // Ignored
    252         }
    253     }
    254 }
    255