Improve the SD card setup flow so that each formatting option is provided in a separate screen with clear description and illustration.Also make sure that guest users do not have any access to formatting options. Test: Manual testing on Pixel Device Screenshot1: https://screenshot.googleplex.com/WJwyxFkBtbSfZmN.png Screenshot2: https://screenshot.googleplex.com/3oBcrrgRsKTxNPC.png Bug: 201252175 Change-Id: I77df55c40fd99cabcfc6128084be035bb5b19531 Change-Id: I757abc6076fcc8f467d8faed9f090bcdd5774ff3
275 lines
10 KiB
Java
275 lines
10 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.util.Log;
|
|
import android.view.Menu;
|
|
import android.view.MenuInflater;
|
|
import android.view.MenuItem;
|
|
import android.widget.Toast;
|
|
|
|
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 {
|
|
|
|
private static final String TAG = "VolumeOptionMenuController";
|
|
private final Context mContext;
|
|
private final Fragment mFragment;
|
|
private final PackageManager mPackageManager;
|
|
@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 StorageEntry mStorageEntry;
|
|
|
|
public VolumeOptionMenuController(Context context, Fragment parent, StorageEntry storageEntry) {
|
|
mContext = context;
|
|
mFragment = parent;
|
|
mPackageManager = context.getPackageManager();
|
|
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);
|
|
|
|
updateOptionsMenu();
|
|
}
|
|
|
|
private void updateOptionsMenu() {
|
|
if (mRename == null || mMount == null || mUnmount == null || mFormat == null
|
|
|| mFormatAsPortable == null || mFormatAsInternal == null || mMigrate == null
|
|
|| mFree == null || mForget == null) {
|
|
Log.d(TAG, "Menu items are not available");
|
|
return;
|
|
}
|
|
|
|
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);
|
|
mFormatAsInternal.setVisible(true);
|
|
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()) {
|
|
boolean mIsPermittedToAdopt = UserManager.get(mContext).isAdminUser()
|
|
&& !ActivityManager.isUserAMonkey();
|
|
|
|
if(!mIsPermittedToAdopt){
|
|
//Notify guest users as to why formatting is disallowed
|
|
Toast.makeText(mFragment.getActivity(),
|
|
R.string.storage_wizard_guest,Toast.LENGTH_LONG).show();
|
|
(mFragment.getActivity()).finish();
|
|
return false;
|
|
}
|
|
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()) {
|
|
final Intent intent = new Intent(mFragment.getActivity(), StorageWizardInit.class);
|
|
intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mStorageEntry.getId());
|
|
mContext.startActivity(intent);
|
|
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;
|
|
|
|
updateOptionsMenu();
|
|
}
|
|
} |