Files
packages_apps_Settings/src/com/android/settings/deviceinfo/VolumeOptionMenuController.java
Arc Wang 87212cf504 Storage Settings crash
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
2022-05-11 13:57:33 +08:00

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;
}
}