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.util.Log; 30 import android.view.Menu; 31 import android.view.MenuInflater; 32 import android.view.MenuItem; 33 import android.widget.Toast; 34 35 import androidx.annotation.VisibleForTesting; 36 import androidx.fragment.app.Fragment; 37 38 import com.android.settings.R; 39 import com.android.settings.core.SubSettingLauncher; 40 import com.android.settings.deviceinfo.storage.StorageEntry; 41 import com.android.settings.deviceinfo.storage.StorageRenameFragment; 42 import com.android.settings.deviceinfo.storage.StorageUtils; 43 import com.android.settings.deviceinfo.storage.StorageUtils.MountTask; 44 import com.android.settings.deviceinfo.storage.StorageUtils.UnmountTask; 45 import com.android.settingslib.core.lifecycle.LifecycleObserver; 46 import com.android.settingslib.core.lifecycle.events.OnCreateOptionsMenu; 47 import com.android.settingslib.core.lifecycle.events.OnOptionsItemSelected; 48 import com.android.settingslib.core.lifecycle.events.OnPrepareOptionsMenu; 49 50 import java.util.Objects; 51 52 /** 53 * Handles the option menu on the Storage settings. 54 */ 55 public class VolumeOptionMenuController implements LifecycleObserver, OnCreateOptionsMenu, 56 OnPrepareOptionsMenu, OnOptionsItemSelected { 57 58 private static final String TAG = "VolumeOptionMenuController"; 59 private final Context mContext; 60 private final Fragment mFragment; 61 private final PackageManager mPackageManager; 62 @VisibleForTesting 63 MenuItem mRename; 64 @VisibleForTesting 65 MenuItem mMount; 66 @VisibleForTesting 67 MenuItem mUnmount; 68 @VisibleForTesting 69 MenuItem mFormat; 70 @VisibleForTesting 71 MenuItem mFormatAsPortable; 72 @VisibleForTesting 73 MenuItem mFormatAsInternal; 74 @VisibleForTesting 75 MenuItem mMigrate; 76 @VisibleForTesting 77 MenuItem mFree; 78 @VisibleForTesting 79 MenuItem mForget; 80 private StorageEntry mStorageEntry; 81 VolumeOptionMenuController(Context context, Fragment parent, StorageEntry storageEntry)82 public VolumeOptionMenuController(Context context, Fragment parent, StorageEntry storageEntry) { 83 mContext = context; 84 mFragment = parent; 85 mPackageManager = context.getPackageManager(); 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 updateOptionsMenu(); 107 } 108 updateOptionsMenu()109 private void updateOptionsMenu() { 110 if (mRename == null || mMount == null || mUnmount == null || mFormat == null 111 || mFormatAsPortable == null || mFormatAsInternal == null || mMigrate == null 112 || mFree == null || mForget == null) { 113 Log.d(TAG, "Menu items are not available"); 114 return; 115 } 116 117 mRename.setVisible(false); 118 mMount.setVisible(false); 119 mUnmount.setVisible(false); 120 mFormat.setVisible(false); 121 mFormatAsPortable.setVisible(false); 122 mFormatAsInternal.setVisible(false); 123 mMigrate.setVisible(false); 124 mFree.setVisible(false); 125 mForget.setVisible(false); 126 127 if (mStorageEntry.isDiskInfoUnsupported()) { 128 mFormat.setVisible(true); 129 return; 130 } 131 if (mStorageEntry.isVolumeRecordMissed()) { 132 mForget.setVisible(true); 133 return; 134 } 135 if (mStorageEntry.isUnmounted()) { 136 mMount.setVisible(true); 137 return; 138 } 139 if (!mStorageEntry.isMounted()) { 140 return; 141 } 142 143 if (mStorageEntry.isPrivate()) { 144 if (!mStorageEntry.isDefaultInternalStorage()) { 145 mRename.setVisible(true); 146 mFormatAsPortable.setVisible(true); 147 } 148 149 // Only offer to migrate when not current storage. 150 final VolumeInfo primaryVolumeInfo = mPackageManager.getPrimaryStorageCurrentVolume(); 151 final VolumeInfo selectedVolumeInfo = mStorageEntry.getVolumeInfo(); 152 mMigrate.setVisible(primaryVolumeInfo != null 153 && primaryVolumeInfo.getType() == VolumeInfo.TYPE_PRIVATE 154 && !Objects.equals(selectedVolumeInfo, primaryVolumeInfo) 155 && primaryVolumeInfo.isMountedWritable()); 156 return; 157 } 158 159 if (mStorageEntry.isPublic()) { 160 mRename.setVisible(true); 161 mUnmount.setVisible(true); 162 mFormatAsInternal.setVisible(true); 163 return; 164 } 165 } 166 167 @Override onOptionsItemSelected(MenuItem menuItem)168 public boolean onOptionsItemSelected(MenuItem menuItem) { 169 if (!mFragment.isAdded()) { 170 return false; 171 } 172 173 final int menuId = menuItem.getItemId(); 174 if (menuId == R.id.storage_mount) { 175 if (mStorageEntry.isUnmounted()) { 176 new MountTask(mFragment.getActivity(), mStorageEntry.getVolumeInfo()).execute(); 177 return true; 178 } 179 return false; 180 } 181 if (menuId == R.id.storage_unmount) { 182 if (mStorageEntry.isMounted()) { 183 if (mStorageEntry.isPublic()) { 184 new UnmountTask(mFragment.getActivity(), 185 mStorageEntry.getVolumeInfo()).execute(); 186 return true; 187 } 188 if (mStorageEntry.isPrivate() && !mStorageEntry.isDefaultInternalStorage()) { 189 final Bundle args = new Bundle(); 190 args.putString(VolumeInfo.EXTRA_VOLUME_ID, mStorageEntry.getId()); 191 new SubSettingLauncher(mContext) 192 .setDestination(PrivateVolumeUnmount.class.getCanonicalName()) 193 .setTitleRes(R.string.storage_menu_unmount) 194 .setSourceMetricsCategory(SettingsEnums.DEVICEINFO_STORAGE) 195 .setArguments(args) 196 .launch(); 197 return true; 198 } 199 } 200 return false; 201 } 202 if (menuId == R.id.storage_rename) { 203 if ((mStorageEntry.isPrivate() && !mStorageEntry.isDefaultInternalStorage()) 204 || mStorageEntry.isPublic()) { 205 StorageRenameFragment.show(mFragment, mStorageEntry.getVolumeInfo()); 206 return true; 207 } 208 return false; 209 } 210 if (menuId == R.id.storage_format) { 211 if (mStorageEntry.isDiskInfoUnsupported() || mStorageEntry.isPublic()) { 212 StorageWizardFormatConfirm.showPublic(mFragment.getActivity(), 213 mStorageEntry.getDiskId()); 214 return true; 215 } 216 return false; 217 } 218 if (menuId == R.id.storage_format_as_portable) { 219 if (mStorageEntry.isPrivate()) { 220 boolean mIsPermittedToAdopt = UserManager.get(mContext).isAdminUser() 221 && !ActivityManager.isUserAMonkey(); 222 223 if(!mIsPermittedToAdopt){ 224 //Notify guest users as to why formatting is disallowed 225 Toast.makeText(mFragment.getActivity(), 226 R.string.storage_wizard_guest,Toast.LENGTH_LONG).show(); 227 (mFragment.getActivity()).finish(); 228 return false; 229 } 230 final Bundle args = new Bundle(); 231 args.putString(VolumeInfo.EXTRA_VOLUME_ID, mStorageEntry.getId()); 232 new SubSettingLauncher(mContext) 233 .setDestination(PrivateVolumeFormat.class.getCanonicalName()) 234 .setTitleRes(R.string.storage_menu_format) 235 .setSourceMetricsCategory(SettingsEnums.DEVICEINFO_STORAGE) 236 .setArguments(args) 237 .launch(); 238 return true; 239 } 240 return false; 241 } 242 if (menuId == R.id.storage_format_as_internal) { 243 if (mStorageEntry.isPublic()) { 244 final Intent intent = new Intent(mFragment.getActivity(), StorageWizardInit.class); 245 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mStorageEntry.getId()); 246 mContext.startActivity(intent); 247 return true; 248 } 249 return false; 250 } 251 if (menuId == R.id.storage_migrate) { 252 if (mStorageEntry.isPrivate()) { 253 final Intent intent = new Intent(mContext, StorageWizardMigrateConfirm.class); 254 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mStorageEntry.getId()); 255 mContext.startActivity(intent); 256 return true; 257 } 258 return false; 259 } 260 if (menuId == R.id.storage_forget) { 261 if (mStorageEntry.isVolumeRecordMissed()) { 262 StorageUtils.launchForgetMissingVolumeRecordFragment(mContext, mStorageEntry); 263 return true; 264 } 265 return false; 266 } 267 return false; 268 } 269 setSelectedStorageEntry(StorageEntry storageEntry)270 public void setSelectedStorageEntry(StorageEntry storageEntry) { 271 mStorageEntry = storageEntry; 272 273 updateOptionsMenu(); 274 } 275 }