1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.deviceinfo; 18 19 import android.app.ActivityManager; 20 import android.app.settings.SettingsEnums; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.pm.PackageManager; 24 import android.os.Bundle; 25 import android.os.UserManager; 26 import android.os.storage.DiskInfo; 27 import android.os.storage.StorageManager; 28 import android.os.storage.VolumeInfo; 29 import android.view.Menu; 30 import android.view.MenuInflater; 31 import android.view.MenuItem; 32 33 import androidx.annotation.VisibleForTesting; 34 import androidx.fragment.app.Fragment; 35 36 import com.android.settings.R; 37 import com.android.settings.core.SubSettingLauncher; 38 import com.android.settings.deviceinfo.storage.StorageEntry; 39 import com.android.settings.deviceinfo.storage.StorageRenameFragment; 40 import com.android.settings.deviceinfo.storage.StorageUtils; 41 import com.android.settings.deviceinfo.storage.StorageUtils.MountTask; 42 import com.android.settings.deviceinfo.storage.StorageUtils.UnmountTask; 43 import com.android.settingslib.core.lifecycle.LifecycleObserver; 44 import com.android.settingslib.core.lifecycle.events.OnCreateOptionsMenu; 45 import com.android.settingslib.core.lifecycle.events.OnOptionsItemSelected; 46 import com.android.settingslib.core.lifecycle.events.OnPrepareOptionsMenu; 47 48 import java.util.Objects; 49 50 /** 51 * Handles the option menu on the Storage settings. 52 */ 53 public class VolumeOptionMenuController implements LifecycleObserver, OnCreateOptionsMenu, 54 OnPrepareOptionsMenu, OnOptionsItemSelected { 55 56 @VisibleForTesting 57 MenuItem mRename; 58 @VisibleForTesting 59 MenuItem mMount; 60 @VisibleForTesting 61 MenuItem mUnmount; 62 @VisibleForTesting 63 MenuItem mFormat; 64 @VisibleForTesting 65 MenuItem mFormatAsPortable; 66 @VisibleForTesting 67 MenuItem mFormatAsInternal; 68 @VisibleForTesting 69 MenuItem mMigrate; 70 @VisibleForTesting 71 MenuItem mFree; 72 @VisibleForTesting 73 MenuItem mForget; 74 75 private final Context mContext; 76 private final Fragment mFragment; 77 private final PackageManager mPackageManager; 78 private final StorageManager mStorageManager; 79 private StorageEntry mStorageEntry; 80 VolumeOptionMenuController(Context context, Fragment parent, StorageEntry storageEntry)81 public VolumeOptionMenuController(Context context, Fragment parent, StorageEntry storageEntry) { 82 mContext = context; 83 mFragment = parent; 84 mPackageManager = context.getPackageManager(); 85 mStorageManager = context.getSystemService(StorageManager.class); 86 mStorageEntry = storageEntry; 87 } 88 89 @Override onCreateOptionsMenu(final Menu menu, final MenuInflater inflater)90 public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { 91 inflater.inflate(R.menu.storage_volume, menu); 92 } 93 94 @Override onPrepareOptionsMenu(Menu menu)95 public void onPrepareOptionsMenu(Menu menu) { 96 mRename = menu.findItem(R.id.storage_rename); 97 mMount = menu.findItem(R.id.storage_mount); 98 mUnmount = menu.findItem(R.id.storage_unmount); 99 mFormat = menu.findItem(R.id.storage_format); 100 mFormatAsPortable = menu.findItem(R.id.storage_format_as_portable); 101 mFormatAsInternal = menu.findItem(R.id.storage_format_as_internal); 102 mMigrate = menu.findItem(R.id.storage_migrate); 103 mFree = menu.findItem(R.id.storage_free); 104 mForget = menu.findItem(R.id.storage_forget); 105 106 mRename.setVisible(false); 107 mMount.setVisible(false); 108 mUnmount.setVisible(false); 109 mFormat.setVisible(false); 110 mFormatAsPortable.setVisible(false); 111 mFormatAsInternal.setVisible(false); 112 mMigrate.setVisible(false); 113 mFree.setVisible(false); 114 mForget.setVisible(false); 115 116 if (mStorageEntry.isDiskInfoUnsupported()) { 117 mFormat.setVisible(true); 118 return; 119 } 120 if (mStorageEntry.isVolumeRecordMissed()) { 121 mForget.setVisible(true); 122 return; 123 } 124 if (mStorageEntry.isUnmounted()) { 125 mMount.setVisible(true); 126 return; 127 } 128 if (!mStorageEntry.isMounted()) { 129 return; 130 } 131 132 if (mStorageEntry.isPrivate()) { 133 if (!mStorageEntry.isDefaultInternalStorage()) { 134 mRename.setVisible(true); 135 mUnmount.setVisible(true); 136 mFormatAsPortable.setVisible(true); 137 } 138 139 // Only offer to migrate when not current storage. 140 final VolumeInfo primaryVolumeInfo = mPackageManager.getPrimaryStorageCurrentVolume(); 141 final VolumeInfo selectedVolumeInfo = mStorageEntry.getVolumeInfo(); 142 mMigrate.setVisible(primaryVolumeInfo != null 143 && primaryVolumeInfo.getType() == VolumeInfo.TYPE_PRIVATE 144 && !Objects.equals(selectedVolumeInfo, primaryVolumeInfo) 145 && primaryVolumeInfo.isMountedWritable()); 146 return; 147 } 148 149 if (mStorageEntry.isPublic()) { 150 mRename.setVisible(true); 151 mUnmount.setVisible(true); 152 mFormat.setVisible(true); 153 final DiskInfo diskInfo = mStorageManager.findDiskById(mStorageEntry.getDiskId()); 154 mFormatAsInternal.setVisible(diskInfo != null 155 && diskInfo.isAdoptable() 156 && UserManager.get(mContext).isAdminUser() 157 && !ActivityManager.isUserAMonkey()); 158 return; 159 } 160 } 161 162 @Override onOptionsItemSelected(MenuItem menuItem)163 public boolean onOptionsItemSelected(MenuItem menuItem) { 164 if (!mFragment.isAdded()) { 165 return false; 166 } 167 168 final int menuId = menuItem.getItemId(); 169 if (menuId == R.id.storage_mount) { 170 if (mStorageEntry.isUnmounted()) { 171 new MountTask(mFragment.getActivity(), mStorageEntry.getVolumeInfo()).execute(); 172 return true; 173 } 174 return false; 175 } 176 if (menuId == R.id.storage_unmount) { 177 if (mStorageEntry.isMounted()) { 178 if (mStorageEntry.isPublic()) { 179 new UnmountTask(mFragment.getActivity(), 180 mStorageEntry.getVolumeInfo()).execute(); 181 return true; 182 } 183 if (mStorageEntry.isPrivate() && !mStorageEntry.isDefaultInternalStorage()) { 184 final Bundle args = new Bundle(); 185 args.putString(VolumeInfo.EXTRA_VOLUME_ID, mStorageEntry.getId()); 186 new SubSettingLauncher(mContext) 187 .setDestination(PrivateVolumeUnmount.class.getCanonicalName()) 188 .setTitleRes(R.string.storage_menu_unmount) 189 .setSourceMetricsCategory(SettingsEnums.DEVICEINFO_STORAGE) 190 .setArguments(args) 191 .launch(); 192 return true; 193 } 194 } 195 return false; 196 } 197 if (menuId == R.id.storage_rename) { 198 if ((mStorageEntry.isPrivate() && !mStorageEntry.isDefaultInternalStorage()) 199 || mStorageEntry.isPublic()) { 200 StorageRenameFragment.show(mFragment, mStorageEntry.getVolumeInfo()); 201 return true; 202 } 203 return false; 204 } 205 if (menuId == R.id.storage_format) { 206 if (mStorageEntry.isDiskInfoUnsupported() || mStorageEntry.isPublic()) { 207 StorageWizardFormatConfirm.showPublic(mFragment.getActivity(), 208 mStorageEntry.getDiskId()); 209 return true; 210 } 211 return false; 212 } 213 if (menuId == R.id.storage_format_as_portable) { 214 if (mStorageEntry.isPrivate()) { 215 final Bundle args = new Bundle(); 216 args.putString(VolumeInfo.EXTRA_VOLUME_ID, mStorageEntry.getId()); 217 new SubSettingLauncher(mContext) 218 .setDestination(PrivateVolumeFormat.class.getCanonicalName()) 219 .setTitleRes(R.string.storage_menu_format) 220 .setSourceMetricsCategory(SettingsEnums.DEVICEINFO_STORAGE) 221 .setArguments(args) 222 .launch(); 223 return true; 224 } 225 return false; 226 } 227 if (menuId == R.id.storage_format_as_internal) { 228 if (mStorageEntry.isPublic()) { 229 StorageWizardFormatConfirm.showPrivate(mFragment.getActivity(), 230 mStorageEntry.getDiskId()); 231 return true; 232 } 233 return false; 234 } 235 if (menuId == R.id.storage_migrate) { 236 if (mStorageEntry.isPrivate()) { 237 final Intent intent = new Intent(mContext, StorageWizardMigrateConfirm.class); 238 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mStorageEntry.getId()); 239 mContext.startActivity(intent); 240 return true; 241 } 242 return false; 243 } 244 if (menuId == R.id.storage_forget) { 245 if (mStorageEntry.isVolumeRecordMissed()) { 246 StorageUtils.launchForgetMissingVolumeRecordFragment(mContext, mStorageEntry); 247 return true; 248 } 249 return false; 250 } 251 return false; 252 } 253 setSelectedStorageEntry(StorageEntry storageEntry)254 public void setSelectedStorageEntry(StorageEntry storageEntry) { 255 mStorageEntry = storageEntry; 256 } 257 } 258