Storage settings will crash because there is no emulated primary volume found after private internal volume is Ejected. Below change in Settings impacted Storage dashboard screen behavior as it Query storage size instead of calculate size of installed APP. Due to this design change now MediaProvider is queried for file sizes, but due to unmounting of primary emulated volume it crashes. We should not show Eject option for private Internal volume. Author: ramneek.kalra@mediatek.com Bug: 230689829 Test: atest com.android.settings.deviceinfo.VolumeOptionMenuControllerTest manual 1. Insert sdcard or generate virtual disk using command : adb shell "sm set-virtual-disk true" 2. Go to Settings -> Storage -> Sdcard/virtual disk -> Format as Internal -> do migrate data 3. After above process completed, go to Settings-> Storage -> sd card/virtual disk and chose Eject menu option. 4. Eject page gets open, Click on Eject button. Change-Id: I98d09f75ee7c2cd5aae10808bd0e0cdf10da7582
257 lines
9.7 KiB
Java
257 lines
9.7 KiB
Java
/*
|
|
* Copyright (C) 2021 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.app.ActivityManager;
|
|
import android.app.settings.SettingsEnums;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.pm.PackageManager;
|
|
import android.os.Bundle;
|
|
import android.os.UserManager;
|
|
import android.os.storage.DiskInfo;
|
|
import android.os.storage.StorageManager;
|
|
import android.os.storage.VolumeInfo;
|
|
import android.view.Menu;
|
|
import android.view.MenuInflater;
|
|
import android.view.MenuItem;
|
|
|
|
import androidx.annotation.VisibleForTesting;
|
|
import androidx.fragment.app.Fragment;
|
|
|
|
import com.android.settings.R;
|
|
import com.android.settings.core.SubSettingLauncher;
|
|
import com.android.settings.deviceinfo.storage.StorageEntry;
|
|
import com.android.settings.deviceinfo.storage.StorageRenameFragment;
|
|
import com.android.settings.deviceinfo.storage.StorageUtils;
|
|
import com.android.settings.deviceinfo.storage.StorageUtils.MountTask;
|
|
import com.android.settings.deviceinfo.storage.StorageUtils.UnmountTask;
|
|
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
|
import com.android.settingslib.core.lifecycle.events.OnCreateOptionsMenu;
|
|
import com.android.settingslib.core.lifecycle.events.OnOptionsItemSelected;
|
|
import com.android.settingslib.core.lifecycle.events.OnPrepareOptionsMenu;
|
|
|
|
import java.util.Objects;
|
|
|
|
/**
|
|
* Handles the option menu on the Storage settings.
|
|
*/
|
|
public class VolumeOptionMenuController implements LifecycleObserver, OnCreateOptionsMenu,
|
|
OnPrepareOptionsMenu, OnOptionsItemSelected {
|
|
|
|
@VisibleForTesting
|
|
MenuItem mRename;
|
|
@VisibleForTesting
|
|
MenuItem mMount;
|
|
@VisibleForTesting
|
|
MenuItem mUnmount;
|
|
@VisibleForTesting
|
|
MenuItem mFormat;
|
|
@VisibleForTesting
|
|
MenuItem mFormatAsPortable;
|
|
@VisibleForTesting
|
|
MenuItem mFormatAsInternal;
|
|
@VisibleForTesting
|
|
MenuItem mMigrate;
|
|
@VisibleForTesting
|
|
MenuItem mFree;
|
|
@VisibleForTesting
|
|
MenuItem mForget;
|
|
|
|
private final Context mContext;
|
|
private final Fragment mFragment;
|
|
private final PackageManager mPackageManager;
|
|
private final StorageManager mStorageManager;
|
|
private StorageEntry mStorageEntry;
|
|
|
|
public VolumeOptionMenuController(Context context, Fragment parent, StorageEntry storageEntry) {
|
|
mContext = context;
|
|
mFragment = parent;
|
|
mPackageManager = context.getPackageManager();
|
|
mStorageManager = context.getSystemService(StorageManager.class);
|
|
mStorageEntry = storageEntry;
|
|
}
|
|
|
|
@Override
|
|
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
|
inflater.inflate(R.menu.storage_volume, menu);
|
|
}
|
|
|
|
@Override
|
|
public void onPrepareOptionsMenu(Menu menu) {
|
|
mRename = menu.findItem(R.id.storage_rename);
|
|
mMount = menu.findItem(R.id.storage_mount);
|
|
mUnmount = menu.findItem(R.id.storage_unmount);
|
|
mFormat = menu.findItem(R.id.storage_format);
|
|
mFormatAsPortable = menu.findItem(R.id.storage_format_as_portable);
|
|
mFormatAsInternal = menu.findItem(R.id.storage_format_as_internal);
|
|
mMigrate = menu.findItem(R.id.storage_migrate);
|
|
mFree = menu.findItem(R.id.storage_free);
|
|
mForget = menu.findItem(R.id.storage_forget);
|
|
|
|
mRename.setVisible(false);
|
|
mMount.setVisible(false);
|
|
mUnmount.setVisible(false);
|
|
mFormat.setVisible(false);
|
|
mFormatAsPortable.setVisible(false);
|
|
mFormatAsInternal.setVisible(false);
|
|
mMigrate.setVisible(false);
|
|
mFree.setVisible(false);
|
|
mForget.setVisible(false);
|
|
|
|
if (mStorageEntry.isDiskInfoUnsupported()) {
|
|
mFormat.setVisible(true);
|
|
return;
|
|
}
|
|
if (mStorageEntry.isVolumeRecordMissed()) {
|
|
mForget.setVisible(true);
|
|
return;
|
|
}
|
|
if (mStorageEntry.isUnmounted()) {
|
|
mMount.setVisible(true);
|
|
return;
|
|
}
|
|
if (!mStorageEntry.isMounted()) {
|
|
return;
|
|
}
|
|
|
|
if (mStorageEntry.isPrivate()) {
|
|
if (!mStorageEntry.isDefaultInternalStorage()) {
|
|
mRename.setVisible(true);
|
|
mFormatAsPortable.setVisible(true);
|
|
}
|
|
|
|
// Only offer to migrate when not current storage.
|
|
final VolumeInfo primaryVolumeInfo = mPackageManager.getPrimaryStorageCurrentVolume();
|
|
final VolumeInfo selectedVolumeInfo = mStorageEntry.getVolumeInfo();
|
|
mMigrate.setVisible(primaryVolumeInfo != null
|
|
&& primaryVolumeInfo.getType() == VolumeInfo.TYPE_PRIVATE
|
|
&& !Objects.equals(selectedVolumeInfo, primaryVolumeInfo)
|
|
&& primaryVolumeInfo.isMountedWritable());
|
|
return;
|
|
}
|
|
|
|
if (mStorageEntry.isPublic()) {
|
|
mRename.setVisible(true);
|
|
mUnmount.setVisible(true);
|
|
mFormat.setVisible(true);
|
|
final DiskInfo diskInfo = mStorageManager.findDiskById(mStorageEntry.getDiskId());
|
|
mFormatAsInternal.setVisible(diskInfo != null
|
|
&& diskInfo.isAdoptable()
|
|
&& UserManager.get(mContext).isAdminUser()
|
|
&& !ActivityManager.isUserAMonkey());
|
|
return;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean onOptionsItemSelected(MenuItem menuItem) {
|
|
if (!mFragment.isAdded()) {
|
|
return false;
|
|
}
|
|
|
|
final int menuId = menuItem.getItemId();
|
|
if (menuId == R.id.storage_mount) {
|
|
if (mStorageEntry.isUnmounted()) {
|
|
new MountTask(mFragment.getActivity(), mStorageEntry.getVolumeInfo()).execute();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
if (menuId == R.id.storage_unmount) {
|
|
if (mStorageEntry.isMounted()) {
|
|
if (mStorageEntry.isPublic()) {
|
|
new UnmountTask(mFragment.getActivity(),
|
|
mStorageEntry.getVolumeInfo()).execute();
|
|
return true;
|
|
}
|
|
if (mStorageEntry.isPrivate() && !mStorageEntry.isDefaultInternalStorage()) {
|
|
final Bundle args = new Bundle();
|
|
args.putString(VolumeInfo.EXTRA_VOLUME_ID, mStorageEntry.getId());
|
|
new SubSettingLauncher(mContext)
|
|
.setDestination(PrivateVolumeUnmount.class.getCanonicalName())
|
|
.setTitleRes(R.string.storage_menu_unmount)
|
|
.setSourceMetricsCategory(SettingsEnums.DEVICEINFO_STORAGE)
|
|
.setArguments(args)
|
|
.launch();
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
if (menuId == R.id.storage_rename) {
|
|
if ((mStorageEntry.isPrivate() && !mStorageEntry.isDefaultInternalStorage())
|
|
|| mStorageEntry.isPublic()) {
|
|
StorageRenameFragment.show(mFragment, mStorageEntry.getVolumeInfo());
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
if (menuId == R.id.storage_format) {
|
|
if (mStorageEntry.isDiskInfoUnsupported() || mStorageEntry.isPublic()) {
|
|
StorageWizardFormatConfirm.showPublic(mFragment.getActivity(),
|
|
mStorageEntry.getDiskId());
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
if (menuId == R.id.storage_format_as_portable) {
|
|
if (mStorageEntry.isPrivate()) {
|
|
final Bundle args = new Bundle();
|
|
args.putString(VolumeInfo.EXTRA_VOLUME_ID, mStorageEntry.getId());
|
|
new SubSettingLauncher(mContext)
|
|
.setDestination(PrivateVolumeFormat.class.getCanonicalName())
|
|
.setTitleRes(R.string.storage_menu_format)
|
|
.setSourceMetricsCategory(SettingsEnums.DEVICEINFO_STORAGE)
|
|
.setArguments(args)
|
|
.launch();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
if (menuId == R.id.storage_format_as_internal) {
|
|
if (mStorageEntry.isPublic()) {
|
|
StorageWizardFormatConfirm.showPrivate(mFragment.getActivity(),
|
|
mStorageEntry.getDiskId());
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
if (menuId == R.id.storage_migrate) {
|
|
if (mStorageEntry.isPrivate()) {
|
|
final Intent intent = new Intent(mContext, StorageWizardMigrateConfirm.class);
|
|
intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mStorageEntry.getId());
|
|
mContext.startActivity(intent);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
if (menuId == R.id.storage_forget) {
|
|
if (mStorageEntry.isVolumeRecordMissed()) {
|
|
StorageUtils.launchForgetMissingVolumeRecordFragment(mContext, mStorageEntry);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void setSelectedStorageEntry(StorageEntry storageEntry) {
|
|
mStorageEntry = storageEntry;
|
|
}
|
|
}
|