Returning to wizard, enable migration.

Bring primary storage migration back into the adoption flow, and
provide a path for long-lived notifications to re-launch into the
Settings app.  Also provide option to initiate migration if skipped
during wizard.  For now, estmiate migration size and time based on
a Class 10 card.

Follow other callback refactoring.

Bug: 19993667
Change-Id: Ia0c28eb114bc6c8066c17b3142ed74f962140c91
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 88c8316..f073b43 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -33,8 +33,9 @@
     public static class VpnSettingsActivity extends SettingsActivity { /* empty */ }
     public static class DateTimeSettingsActivity extends SettingsActivity { /* empty */ }
     public static class StorageSettingsActivity extends SettingsActivity { /* empty */ }
-    public static class PublicVolumeSettingsActivity extends SettingsActivity { /* empty */ }
     public static class PrivateVolumeForgetActivity extends SettingsActivity { /* empty */ }
+    public static class PrivateVolumeSettingsActivity extends SettingsActivity { /* empty */ }
+    public static class PublicVolumeSettingsActivity extends SettingsActivity { /* empty */ }
     public static class WifiSettingsActivity extends SettingsActivity { /* empty */ }
     public static class WifiP2pSettingsActivity extends SettingsActivity { /* empty */ }
     public static class InputMethodAndLanguageSettingsActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 5e1acb1..1ae923a 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -84,6 +84,7 @@
 import com.android.settings.dashboard.NoHomeDialogFragment;
 import com.android.settings.dashboard.SearchResultsSummary;
 import com.android.settings.deviceinfo.PrivateVolumeForget;
+import com.android.settings.deviceinfo.PrivateVolumeSettings;
 import com.android.settings.deviceinfo.PublicVolumeSettings;
 import com.android.settings.deviceinfo.StorageSettings;
 import com.android.settings.deviceinfo.UsbSettings;
@@ -310,8 +311,9 @@
             com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment.class.getName(),
             TextToSpeechSettings.class.getName(),
             StorageSettings.class.getName(),
-            PublicVolumeSettings.class.getName(),
             PrivateVolumeForget.class.getName(),
+            PrivateVolumeSettings.class.getName(),
+            PublicVolumeSettings.class.getName(),
             DevelopmentSettings.class.getName(),
             UsbSettings.class.getName(),
             AndroidBeam.class.getName(),
diff --git a/src/com/android/settings/deviceinfo/MigrateEstimateTask.java b/src/com/android/settings/deviceinfo/MigrateEstimateTask.java
new file mode 100644
index 0000000..bc8ff92
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/MigrateEstimateTask.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deviceinfo;
+
+import static com.android.settings.deviceinfo.StorageSettings.TAG;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.net.TrafficStats;
+import android.os.AsyncTask;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.telecom.Log;
+import android.text.format.DateUtils;
+import android.text.format.Formatter;
+
+import com.android.internal.app.IMediaContainerService;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public abstract class MigrateEstimateTask extends AsyncTask<Void, Void, Long> implements
+        ServiceConnection {
+    private static final String EXTRA_SIZE_BYTES = "size_bytes";
+
+    private static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
+            "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
+
+    /**
+     * Assume roughly a Class 10 card.
+     */
+    private static final long SPEED_ESTIMATE_BPS = 10 * TrafficStats.MB_IN_BYTES;
+
+    private final Context mContext;
+    private final StorageManager mStorage;
+
+    private final CountDownLatch mConnected = new CountDownLatch(1);
+    private IMediaContainerService mService;
+
+    private long mSizeBytes = -1;
+    private long mTimeMillis = -1;
+
+    public MigrateEstimateTask(Context context) {
+        mContext = context;
+        mStorage = context.getSystemService(StorageManager.class);
+    }
+
+    public void copyFrom(Intent intent) {
+        mSizeBytes = intent.getLongExtra(EXTRA_SIZE_BYTES, -1);
+    }
+
+    public void copyTo(Intent intent) {
+        intent.putExtra(EXTRA_SIZE_BYTES, mSizeBytes);
+    }
+
+    @Override
+    protected Long doInBackground(Void... params) {
+        if (mSizeBytes != -1) {
+            return mSizeBytes;
+        }
+
+        final VolumeInfo privateVol = mContext.getPackageManager().getPrimaryStorageCurrentVolume();
+        final VolumeInfo emulatedVol = mStorage.findEmulatedForPrivate(privateVol);
+
+        final String path = emulatedVol.getPath().getAbsolutePath();
+        Log.d(TAG, "Estimating for current path " + path);
+
+        final Intent intent = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
+        mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE, UserHandle.OWNER);
+
+        try {
+            if (mConnected.await(15, TimeUnit.SECONDS)) {
+                return mService.calculateDirectorySize(path);
+            }
+        } catch (InterruptedException | RemoteException e) {
+            Log.w(TAG, "Failed to measure " + path);
+        } finally {
+            mContext.unbindService(this);
+        }
+
+        return -1L;
+    }
+
+    @Override
+    protected void onPostExecute(Long result) {
+        mSizeBytes = result;
+        mTimeMillis = (mSizeBytes * DateUtils.SECOND_IN_MILLIS) / SPEED_ESTIMATE_BPS;
+
+        final String size = Formatter.formatFileSize(mContext, mSizeBytes);
+        final String time = DateUtils.formatDuration(mTimeMillis).toString();
+        onPostExecute(size, time);
+    }
+
+    public abstract void onPostExecute(String size, String time);
+
+    @Override
+    public void onServiceConnected(ComponentName name, IBinder service) {
+        mService = IMediaContainerService.Stub.asInterface(service);
+        mConnected.countDown();
+    }
+
+    @Override
+    public void onServiceDisconnected(ComponentName name) {
+        // Ignored; we leave service in place for the background thread to
+        // run into DeadObjectException
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/PrivateVolumeFormat.java b/src/com/android/settings/deviceinfo/PrivateVolumeFormat.java
index e16778f..669f2ed 100644
--- a/src/com/android/settings/deviceinfo/PrivateVolumeFormat.java
+++ b/src/com/android/settings/deviceinfo/PrivateVolumeFormat.java
@@ -67,6 +67,7 @@
             final Intent intent = new Intent(getActivity(), StorageWizardFormatProgress.class);
             intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
             intent.putExtra(StorageWizardFormatConfirm.EXTRA_FORMAT_PRIVATE, false);
+            intent.putExtra(StorageWizardFormatConfirm.EXTRA_FORGET_UUID, mVolume.getFsUuid());
             startActivity(intent);
             getActivity().finish();
         }
diff --git a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
index 3e2b570..e5f50dd 100644
--- a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
+++ b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
@@ -34,6 +34,7 @@
 import android.os.Environment;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.DiskInfo;
 import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
@@ -271,6 +272,7 @@
         final MenuItem mount = menu.findItem(R.id.storage_mount);
         final MenuItem unmount = menu.findItem(R.id.storage_unmount);
         final MenuItem format = menu.findItem(R.id.storage_format);
+        final MenuItem migrate = menu.findItem(R.id.storage_migrate);
         final MenuItem usb = menu.findItem(R.id.storage_usb);
 
         // Actions live in menu for non-internal private volumes; they're shown
@@ -287,6 +289,11 @@
             format.setVisible(true);
         }
 
+        // Only offer to migrate when not current storage
+        final VolumeInfo privateVol = getActivity().getPackageManager()
+                .getPrimaryStorageCurrentVolume();
+        migrate.setVisible(!Objects.equals(mVolume, privateVol));
+
         // TODO: show usb if we jumped past first screen
         usb.setVisible(false);
     }
@@ -312,6 +319,11 @@
                 startFragment(this, PrivateVolumeFormat.class.getCanonicalName(),
                         R.string.storage_menu_format, 0, args);
                 return true;
+            case R.id.storage_migrate:
+                final Intent intent = new Intent(context, StorageWizardMigrateConfirm.class);
+                intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mVolume.getId());
+                startActivity(intent);
+                return true;
             case R.id.storage_usb:
                 startFragment(this, UsbSettings.class.getCanonicalName(),
                         R.string.storage_title_usb, 0, null);
@@ -442,8 +454,8 @@
         }
 
         @Override
-        public void onVolumeMetadataChanged(String fsUuid) {
-            if (Objects.equals(mVolume.getFsUuid(), fsUuid)) {
+        public void onVolumeRecordChanged(VolumeRecord rec) {
+            if (Objects.equals(mVolume.getFsUuid(), rec.getFsUuid())) {
                 mVolume = mStorageManager.findVolumeById(mVolumeId);
                 update();
             }
diff --git a/src/com/android/settings/deviceinfo/PublicVolumeSettings.java b/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
index 1d7991d..dee644a 100644
--- a/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
+++ b/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
@@ -24,6 +24,7 @@
 import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
+import android.os.storage.VolumeRecord;
 import android.preference.Preference;
 import android.preference.PreferenceScreen;
 import android.provider.DocumentsContract;
@@ -220,8 +221,8 @@
         }
 
         @Override
-        public void onVolumeMetadataChanged(String fsUuid) {
-            if (Objects.equals(mVolume.getFsUuid(), fsUuid)) {
+        public void onVolumeRecordChanged(VolumeRecord rec) {
+            if (Objects.equals(mVolume.getFsUuid(), rec.getFsUuid())) {
                 mVolume = mStorageManager.findVolumeById(mVolumeId);
                 update();
             }
diff --git a/src/com/android/settings/deviceinfo/StorageWizardBase.java b/src/com/android/settings/deviceinfo/StorageWizardBase.java
index 42c74a5..31f7af4 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardBase.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardBase.java
@@ -35,6 +35,8 @@
 import com.android.setupwizardlib.view.NavigationBar.NavigationBarListener;
 
 import java.text.NumberFormat;
+import java.util.List;
+import java.util.Objects;
 
 public abstract class StorageWizardBase extends Activity implements NavigationBarListener {
     protected StorageManager mStorage;
@@ -56,7 +58,7 @@
         final String diskId = getIntent().getStringExtra(DiskInfo.EXTRA_DISK_ID);
         if (!TextUtils.isEmpty(diskId)) {
             mDisk = mStorage.findDiskById(diskId);
-        } else {
+        } else if (mVolume != null) {
             mDisk = mVolume.getDisk();
         }
 
@@ -130,4 +132,14 @@
     public void onNavigateNext() {
         throw new UnsupportedOperationException();
     }
+
+    protected VolumeInfo findFirstVolume(int type) {
+        final List<VolumeInfo> vols = mStorage.getVolumes();
+        for (VolumeInfo vol : vols) {
+            if (Objects.equals(mDisk.getId(), vol.getDiskId()) && (vol.getType() == type)) {
+                return vol;
+            }
+        }
+        return null;
+    }
 }
diff --git a/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java b/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
index 81073d6..33f2173 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
@@ -25,6 +25,7 @@
 
 public class StorageWizardFormatConfirm extends StorageWizardBase {
     public static final String EXTRA_FORMAT_PRIVATE = "format_private";
+    public static final String EXTRA_FORGET_UUID = "forget_uuid";
 
     private boolean mFormatPrivate;
 
@@ -56,6 +57,7 @@
         final Intent intent = new Intent(this, StorageWizardFormatProgress.class);
         intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
         intent.putExtra(EXTRA_FORMAT_PRIVATE, mFormatPrivate);
+        intent.putExtra(EXTRA_FORGET_UUID, getIntent().getStringExtra(EXTRA_FORGET_UUID));
         startActivity(intent);
         finishAffinity();
     }
diff --git a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
index e60bbcf..9ab714a 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
@@ -23,6 +23,8 @@
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.storage.DiskInfo;
+import android.os.storage.VolumeInfo;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
 import android.widget.Toast;
@@ -72,12 +74,25 @@
         protected void onPostExecute(Exception e) {
             final Context context = StorageWizardFormatProgress.this;
             if (e == null) {
+                final String forgetUuid = getIntent().getStringExtra(
+                        StorageWizardFormatConfirm.EXTRA_FORGET_UUID);
+                if (!TextUtils.isEmpty(forgetUuid)) {
+                    mStorage.forgetVolume(forgetUuid);
+                }
+
+                final boolean offerMigrate;
                 if (mFormatPrivate) {
-                    // TODO: bring back migration once implemented
-//                    final Intent intent = new Intent(context, StorageWizardMigrate.class);
-//                    intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
-//                    startActivity(intent);
-                    final Intent intent = new Intent(context, StorageWizardReady.class);
+                    // Offer to migrate only if storage is currently internal
+                    final VolumeInfo privateVol = getPackageManager()
+                            .getPrimaryStorageCurrentVolume();
+                    offerMigrate = (privateVol != null
+                            && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.getId()));
+                } else {
+                    offerMigrate = false;
+                }
+
+                if (offerMigrate) {
+                    final Intent intent = new Intent(context, StorageWizardMigrate.class);
                     intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
                     startActivity(intent);
                 } else {
diff --git a/src/com/android/settings/deviceinfo/StorageWizardMigrate.java b/src/com/android/settings/deviceinfo/StorageWizardMigrate.java
index 4d42613..7831a07 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardMigrate.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardMigrate.java
@@ -19,8 +19,6 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.storage.DiskInfo;
-import android.text.format.DateUtils;
-import android.text.format.Formatter;
 import android.widget.CompoundButton;
 import android.widget.CompoundButton.OnCheckedChangeListener;
 import android.widget.RadioButton;
@@ -29,6 +27,8 @@
 import com.android.settings.R;
 
 public class StorageWizardMigrate extends StorageWizardBase {
+    private MigrateEstimateTask mEstimate;
+
     private RadioButton mRadioNow;
     private RadioButton mRadioLater;
 
@@ -39,11 +39,8 @@
 
         Preconditions.checkNotNull(mDisk);
 
-        final String time = DateUtils.formatDuration(0).toString();
-        final String size = Formatter.formatFileSize(this, 0);
-
         setHeaderText(R.string.storage_wizard_migrate_title, mDisk.getDescription());
-        setBodyText(R.string.storage_wizard_migrate_body, mDisk.getDescription(), time, size);
+        setBodyText(R.string.memory_calculating_size);
 
         mRadioNow = (RadioButton) findViewById(R.id.storage_wizard_migrate_now);
         mRadioLater = (RadioButton) findViewById(R.id.storage_wizard_migrate_later);
@@ -52,6 +49,17 @@
         mRadioLater.setOnCheckedChangeListener(mRadioListener);
 
         mRadioNow.setChecked(true);
+
+        mEstimate = new MigrateEstimateTask(this) {
+            @Override
+            public void onPostExecute(String size, String time) {
+                setBodyText(R.string.storage_wizard_migrate_body,
+                        mDisk.getDescription(), time, size);
+            }
+        };
+
+        mEstimate.copyFrom(getIntent());
+        mEstimate.execute();
     }
 
     private final OnCheckedChangeListener mRadioListener = new OnCheckedChangeListener() {
@@ -72,6 +80,7 @@
         if (mRadioNow.isChecked()) {
             final Intent intent = new Intent(this, StorageWizardMigrateConfirm.class);
             intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
+            mEstimate.copyTo(intent);
             startActivity(intent);
         } else if (mRadioLater.isChecked()) {
             final Intent intent = new Intent(this, StorageWizardReady.class);
diff --git a/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java b/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java
index 9aa1441..daa76d7 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java
@@ -17,36 +17,54 @@
 package com.android.settings.deviceinfo;
 
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
-import android.os.storage.DiskInfo;
-import android.text.format.DateUtils;
-import android.text.format.Formatter;
+import android.os.storage.VolumeInfo;
 
-import com.android.internal.util.Preconditions;
 import com.android.settings.R;
 
 public class StorageWizardMigrateConfirm extends StorageWizardBase {
+    private MigrateEstimateTask mEstimate;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.storage_wizard_generic);
 
-        Preconditions.checkNotNull(mDisk);
+        // When called with just disk, find the first private volume
+        if (mVolume == null) {
+            mVolume = findFirstVolume(VolumeInfo.TYPE_PRIVATE);
+        }
 
-        final String time = DateUtils.formatDuration(0).toString();
-        final String size = Formatter.formatFileSize(this, 0);
+        final VolumeInfo sourceVol = getPackageManager().getPrimaryStorageCurrentVolume();
+        final String sourceDescrip = mStorage.getBestVolumeDescription(sourceVol);
+        final String targetDescrip = mStorage.getBestVolumeDescription(mVolume);
 
-        setHeaderText(R.string.storage_wizard_migrate_confirm_title, mDisk.getDescription());
-        setBodyText(R.string.storage_wizard_migrate_confirm_body, time, size);
-        setSecondaryBodyText(R.string.storage_wizard_migrate_details, mDisk.getDescription());
+        setHeaderText(R.string.storage_wizard_migrate_confirm_title, targetDescrip);
+        setBodyText(R.string.memory_calculating_size);
+        setSecondaryBodyText(R.string.storage_wizard_migrate_details, targetDescrip);
+
+        mEstimate = new MigrateEstimateTask(this) {
+            @Override
+            public void onPostExecute(String size, String time) {
+                setBodyText(R.string.storage_wizard_migrate_confirm_body, time, size,
+                        sourceDescrip);
+            }
+        };
+
+        mEstimate.copyFrom(getIntent());
+        mEstimate.execute();
 
         getNextButton().setText(R.string.storage_wizard_migrate_confirm_next);
     }
 
     @Override
     public void onNavigateNext() {
+        final int moveId = getPackageManager().movePrimaryStorage(mVolume);
+
         final Intent intent = new Intent(this, StorageWizardMigrateProgress.class);
-        intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
+        intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mVolume.getId());
+        intent.putExtra(PackageManager.EXTRA_MOVE_ID, moveId);
         startActivity(intent);
         finishAffinity();
     }
diff --git a/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java b/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java
index b53b250..70d93f8 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java
@@ -16,13 +16,15 @@
 
 package com.android.settings.deviceinfo;
 
+import static android.content.pm.PackageManager.EXTRA_MOVE_ID;
 import static com.android.settings.deviceinfo.StorageSettings.TAG;
 
 import android.content.Context;
 import android.content.Intent;
-import android.os.AsyncTask;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.MoveCallback;
 import android.os.Bundle;
-import android.os.SystemClock;
+import android.os.Handler;
 import android.os.storage.DiskInfo;
 import android.util.Log;
 import android.view.View;
@@ -32,45 +34,51 @@
 import com.android.settings.R;
 
 public class StorageWizardMigrateProgress extends StorageWizardBase {
+    private int mMoveId;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.storage_wizard_progress);
 
-        Preconditions.checkNotNull(mDisk);
+        Preconditions.checkNotNull(mVolume);
 
-        setHeaderText(R.string.storage_wizard_migrate_progress_title, mDisk.getDescription());
-        setBodyText(R.string.storage_wizard_migrate_details, mDisk.getDescription());
+        mMoveId = getIntent().getIntExtra(EXTRA_MOVE_ID, -1);
 
-        setCurrentProgress(20);
+        final String descrip = mStorage.getBestVolumeDescription(mVolume);
+        setHeaderText(R.string.storage_wizard_migrate_progress_title, descrip);
+        setBodyText(R.string.storage_wizard_migrate_details, descrip);
 
         getNextButton().setVisibility(View.GONE);
 
-        new MigrateTask().execute();
+        // Register for updates and push through current status
+        getPackageManager().registerMoveCallback(mCallback, new Handler());
+        mCallback.onStatusChanged(mMoveId, getPackageManager().getMoveStatus(mMoveId), -1);
     }
 
-    public class MigrateTask extends AsyncTask<Void, Void, Exception> {
+    private final MoveCallback mCallback = new MoveCallback() {
         @Override
-        protected Exception doInBackground(Void... params) {
-            // TODO: wire up migration
-            SystemClock.sleep(2000);
-            return null;
-        }
+        public void onStatusChanged(int moveId, int status, long estMillis) {
+            if (mMoveId != moveId) return;
 
-        @Override
-        protected void onPostExecute(Exception e) {
             final Context context = StorageWizardMigrateProgress.this;
-            if (e == null) {
-                final Intent intent = new Intent(context, StorageWizardReady.class);
-                intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
-                startActivity(intent);
+            if (PackageManager.isMoveStatusFinished(status)) {
+                Log.d(TAG, "Finished with status " + status);
+                if (status == PackageManager.MOVE_SUCCEEDED) {
+                    if (mDisk != null) {
+                        final Intent intent = new Intent(context, StorageWizardReady.class);
+                        intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
+                        startActivity(intent);
+                    }
+                } else {
+                    Toast.makeText(context, getString(R.string.insufficient_storage),
+                            Toast.LENGTH_LONG).show();
+                }
                 finishAffinity();
 
             } else {
-                Log.e(TAG, "Failed to migrate", e);
-                Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show();
-                finishAffinity();
+                setCurrentProgress(status);
             }
         }
-    }
+    };
 }
diff --git a/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java b/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java
index 1202b9e..86e623f 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java
@@ -49,7 +49,7 @@
 
         // Register for updates and push through current status
         getPackageManager().registerMoveCallback(mCallback, new Handler());
-        mCallback.onStatusChanged(mMoveId, null, getPackageManager().getMoveStatus(mMoveId), -1);
+        mCallback.onStatusChanged(mMoveId, getPackageManager().getMoveStatus(mMoveId), -1);
     }
 
     @Override
@@ -60,7 +60,7 @@
 
     private final MoveCallback mCallback = new MoveCallback() {
         @Override
-        public void onStatusChanged(int moveId, String moveTitle, int status, long estMillis) {
+        public void onStatusChanged(int moveId, int status, long estMillis) {
             if (mMoveId != moveId) return;
 
             if (PackageManager.isMoveStatusFinished(status)) {
diff --git a/src/com/android/settings/deviceinfo/StorageWizardReady.java b/src/com/android/settings/deviceinfo/StorageWizardReady.java
index 26038ce..6d8846b 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardReady.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardReady.java
@@ -22,9 +22,6 @@
 import com.android.internal.util.Preconditions;
 import com.android.settings.R;
 
-import java.util.List;
-import java.util.Objects;
-
 public class StorageWizardReady extends StorageWizardBase {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -37,19 +34,14 @@
 
         // TODO: handle mixed partition cases instead of just guessing based on
         // first volume type we encounter
-        final List<VolumeInfo> vols = mStorage.getVolumes();
-        for (VolumeInfo vol : vols) {
-            if (!Objects.equals(mDisk.getId(), vol.getDiskId())) continue;
-
-            if (vol.getType() == VolumeInfo.TYPE_PUBLIC) {
-                setBodyText(R.string.storage_wizard_ready_external_body,
-                        mDisk.getDescription());
-                break;
-            } else if (vol.getType() == VolumeInfo.TYPE_PRIVATE) {
-                setBodyText(R.string.storage_wizard_ready_internal_body,
-                        mDisk.getDescription());
-                break;
-            }
+        final VolumeInfo publicVol = findFirstVolume(VolumeInfo.TYPE_PUBLIC);
+        final VolumeInfo privateVol = findFirstVolume(VolumeInfo.TYPE_PRIVATE);
+        if (publicVol != null) {
+            setBodyText(R.string.storage_wizard_ready_external_body,
+                    mDisk.getDescription());
+        } else if (privateVol != null) {
+            setBodyText(R.string.storage_wizard_ready_internal_body,
+                    mDisk.getDescription());
         }
 
         getNextButton().setText(R.string.done);