Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f6b12274 authored by Daniel Nishi's avatar Daniel Nishi
Browse files

Re-add the option to migrate data back.

Currently, users can use an SD card or USB drive and adopt it as
internal storage using existing flows. They can manage this drive
perfectly fine using the old storage screen, which is still around.

One functionality that was lost was the ability to migrate data from
the adopted drive back to the private internal storage. This appeared
in a dropdown in the old storage settings.

By duplicating the code to create just that specific menu item and its
click behavior, we can restore this functionality to the new storage
view.

Change-Id: Id0e01c560e7249acccfe86c5da44466dd58fe5d4
Merged-In: I4b8c06912d2c0b2c5be5bce8b217d45accf34d4b
Fixes: 35926028
Test: Settings Robotest
parent 28e35fcf
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.content.pm.IPackageDeleteObserver;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.UserHandle;
import android.os.storage.VolumeInfo;

import java.util.List;

@@ -105,4 +106,8 @@ public interface PackageManagerWrapper {
     */
    void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int flags,
            int userId);
    /**
     * Calls {@code PackageManager.getPrimaryStorageCurrentVolume}
     */
    VolumeInfo getPrimaryStorageCurrentVolume();
}
+6 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.content.pm.IPackageDeleteObserver;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.UserHandle;
import android.os.storage.VolumeInfo;

import java.util.List;

@@ -97,4 +98,9 @@ public class PackageManagerWrapperImpl implements PackageManagerWrapper {
            int userId) {
        mPm.deletePackageAsUser(packageName, observer, flags, userId);
    }

    @Override
    public VolumeInfo getPrimaryStorageCurrentVolume() {
        return mPm.getPrimaryStorageCurrentVolume();
    }
}
+85 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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 android.content.Context;
import android.content.Intent;
import android.os.storage.VolumeInfo;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

import com.android.settings.R;
import com.android.settings.applications.PackageManagerWrapper;
import com.android.settings.core.lifecycle.Lifecycle;
import com.android.settings.core.lifecycle.LifecycleObserver;
import com.android.settings.core.lifecycle.events.OnCreateOptionsMenu;
import com.android.settings.core.lifecycle.events.OnOptionsItemSelected;
import com.android.settings.core.lifecycle.events.OnPrepareOptionsMenu;

import java.util.Objects;

/**
 * Handles the option menu on the Storage settings.
 */
public class PrivateVolumeOptionMenuController implements LifecycleObserver, OnCreateOptionsMenu,
        OnPrepareOptionsMenu, OnOptionsItemSelected {
    private static final int OPTIONS_MENU_MIGRATE_DATA = 100;

    private Context mContext;
    private VolumeInfo mVolumeInfo;
    private PackageManagerWrapper mPm;

    public PrivateVolumeOptionMenuController(
            Context context, VolumeInfo volumeInfo, PackageManagerWrapper packageManager) {
        mContext = context;
        mVolumeInfo = volumeInfo;
        mPm = packageManager;
    }

    @Override
    public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
        menu.add(Menu.NONE, OPTIONS_MENU_MIGRATE_DATA, 0, R.string.storage_menu_migrate);
    }

    @Override
    public void onPrepareOptionsMenu(Menu menu) {
        if (mVolumeInfo == null) {
            return;
        }

        // Only offer to migrate when not current storage
        final VolumeInfo privateVol = mPm.getPrimaryStorageCurrentVolume();
        final MenuItem migrate = menu.findItem(OPTIONS_MENU_MIGRATE_DATA);
        if (migrate != null) {
            migrate.setVisible((privateVol != null)
                    && (privateVol.getType() == VolumeInfo.TYPE_PRIVATE)
                    && !Objects.equals(mVolumeInfo, privateVol));
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem menuItem) {
        if (menuItem.getItemId() == OPTIONS_MENU_MIGRATE_DATA) {
            final Intent intent = new Intent(mContext, StorageWizardMigrateConfirm.class);
            intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mVolumeInfo.getId());
            mContext.startActivity(intent);
            return true;
        }
        return false;
    }
}
+19 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.settings.deviceinfo;

import android.app.LoaderManager;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
import android.os.Bundle;
import android.os.UserHandle;
@@ -25,11 +26,17 @@ import android.os.UserManager;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.provider.SearchIndexableResource;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.util.SparseArray;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.applications.PackageManagerWrapper;
import com.android.settings.applications.PackageManagerWrapperImpl;
import com.android.settings.applications.UserManagerWrapper;
import com.android.settings.applications.UserManagerWrapperImpl;
@@ -48,16 +55,19 @@ import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

public class StorageDashboardFragment extends DashboardFragment
    implements LoaderManager.LoaderCallbacks<SparseArray<StorageAsyncLoader.AppsStorageResult>> {
    private static final String TAG = "StorageDashboardFrag";
    private static final int STORAGE_JOB_ID = 0;
    private static final int OPTIONS_MENU_MIGRATE_DATA = 100;

    private VolumeInfo mVolume;

    private StorageSummaryDonutPreferenceController mSummaryController;
    private StorageItemPreferenceController mPreferenceController;
    private PrivateVolumeOptionMenuController mOptionMenuController;
    private List<PreferenceController> mSecondaryUsers;

    @Override
@@ -101,6 +111,9 @@ public class StorageDashboardFragment extends DashboardFragment
            return;
        }

        mOptionMenuController = new PrivateVolumeOptionMenuController(
                context, mVolume, new PackageManagerWrapperImpl(context.getPackageManager()));

        final long sharedDataSize = mVolume.getPath().getTotalSpace();
        long totalSize = sm.getPrimaryStorageSize();
        long systemSize = totalSize - sharedDataSize;
@@ -161,10 +174,16 @@ public class StorageDashboardFragment extends DashboardFragment
                new AutomaticStorageManagementSwitchPreferenceController(
                        context, mMetricsFeatureProvider, getFragmentManager());
        getLifecycle().addObserver(asmController);
        getLifecycle().addObserver(mOptionMenuController);
        controllers.add(asmController);
        return controllers;
    }

    @VisibleForTesting
    protected void setVolume(VolumeInfo info) {
        mVolume = info;
    }

    /**
     * Updates the secondary user controller sizes.
     */
+116 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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.google.common.truth.Truth.assertThat;

import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.os.storage.VolumeInfo;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

import com.android.settings.R;
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settings.applications.PackageManagerWrapper;
import com.android.settings.testutils.FakeFeatureFactory;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;

@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class PrivateVolumeOptionMenuControllerTest {
    @Mock
    private MenuItem mMigrateMenuItem;
    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
    private Menu mMenu;
    @Mock
    private MenuInflater mMenuInflater;
    @Mock
    private PackageManagerWrapper mPm;
    @Mock
    private VolumeInfo mVolumeInfo;
    @Mock
    private VolumeInfo mPrimaryInfo;

    private PrivateVolumeOptionMenuController mController;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);

        when(mVolumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
        when(mPrimaryInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
        when(mMenu.findItem(anyInt())).thenReturn(mMigrateMenuItem);
        when(mMigrateMenuItem.getItemId()).thenReturn(100);

        mController = new PrivateVolumeOptionMenuController(
                RuntimeEnvironment.application, mPrimaryInfo, mPm);
    }

    @Test
    public void testMigrateDataMenuItemIsAdded() {
        mController.onCreateOptionsMenu(mMenu, mMenuInflater);

        verify(mMenu).add(Menu.NONE, 100, Menu.NONE, R.string.storage_menu_migrate);
    }

    @Test
    public void testMigrateDataIsNotVisibleNormally() {
        when(mPm.getPrimaryStorageCurrentVolume()).thenReturn(mPrimaryInfo);

        mController.onCreateOptionsMenu(mMenu, mMenuInflater);
        mController.onPrepareOptionsMenu(mMenu);

        verify(mMigrateMenuItem).setVisible(false);
    }

    @Test
    public void testMigrateDataIsVisibleWhenExternalVolumeIsPrimary() {
        when(mPm.getPrimaryStorageCurrentVolume()).thenReturn(mVolumeInfo);

        mController.onCreateOptionsMenu(mMenu, mMenuInflater);
        mController.onPrepareOptionsMenu(mMenu);

        verify(mMigrateMenuItem).setVisible(true);
    }

    @Test
    public void testMigrateDataGoesToMigrateWizard() {
        when(mPm.getPrimaryStorageCurrentVolume()).thenReturn(mVolumeInfo);

        mController.onCreateOptionsMenu(mMenu, mMenuInflater);
        mController.onPrepareOptionsMenu(mMenu);

        assertThat(mController.onOptionsItemSelected(mMigrateMenuItem)).isTrue();
        assertThat(ShadowApplication.getInstance()
                .getNextStartedActivity().getComponent().getClassName())
                .isEqualTo(StorageWizardMigrateConfirm.class.getName());
    }
}
Loading