1 /* 2 * Copyright (C) 2017 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.tv.settings.device.storage; 18 19 import android.app.ActivityManager; 20 import android.content.BroadcastReceiver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.pm.UserInfo; 24 import android.os.UserHandle; 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.os.storage.VolumeRecord; 30 import android.provider.Settings; 31 import android.text.TextUtils; 32 import android.util.Log; 33 import android.widget.Toast; 34 35 import com.android.tv.settings.R; 36 37 import java.util.List; 38 39 /** 40 * Broadcast receiver invoked when a USB device is connected/disconnected/scanned. 41 */ 42 public class DiskReceiver extends BroadcastReceiver { 43 private static final String TAG = "DiskReceiver"; 44 45 private StorageManager mStorageManager; 46 47 @Override 48 public void onReceive(Context context, Intent intent) { 49 final UserManager userManager = 50 (UserManager) context.getSystemService(Context.USER_SERVICE); 51 final UserInfo userInfo = userManager.getUserInfo(UserHandle.myUserId()); 52 53 if (userInfo.isRestricted() 54 || ActivityManager.getCurrentUser() != UserHandle.myUserId()) { 55 Log.d(TAG, "Ignoring storage notification: wrong user"); 56 return; 57 } 58 59 if (Settings.Secure.getInt(context.getContentResolver(), 60 Settings.Secure.USER_SETUP_COMPLETE, 0) == 0) { 61 Log.d(TAG, "Ignoring storage notification: setup not complete"); 62 return; 63 } 64 65 mStorageManager = context.getSystemService(StorageManager.class); 66 67 if (TextUtils.equals(intent.getAction(), VolumeInfo.ACTION_VOLUME_STATE_CHANGED)) { 68 final int state = intent.getIntExtra(VolumeInfo.EXTRA_VOLUME_STATE, -1); 69 if (state == VolumeInfo.STATE_MOUNTED 70 || state == VolumeInfo.STATE_MOUNTED_READ_ONLY) { 71 handleMount(context, intent); 72 } else if (state == VolumeInfo.STATE_UNMOUNTED 73 || state == VolumeInfo.STATE_BAD_REMOVAL) { 74 handleUnmount(context, intent); 75 } 76 } else if (TextUtils.equals(intent.getAction(), 77 "com.google.android.tungsten.setupwraith.TV_SETTINGS_POST_SETUP")) { 78 handleSetupComplete(context); 79 } 80 } 81 82 private void handleMount(Context context, Intent intent) { 83 final String volumeId = intent.getStringExtra(VolumeInfo.EXTRA_VOLUME_ID); 84 85 final List<VolumeInfo> volumeInfos = mStorageManager.getVolumes(); 86 for (final VolumeInfo info : volumeInfos) { 87 if (!TextUtils.equals(info.getId(), volumeId)) { 88 continue; 89 } 90 final String uuid = info.getFsUuid(); 91 Log.d(TAG, "Scanning volume: " + info); 92 if (info.getType() == VolumeInfo.TYPE_PRIVATE 93 && !TextUtils.equals(volumeId, VolumeInfo.ID_PRIVATE_INTERNAL)) { 94 Toast.makeText(context, R.string.storage_mount_adopted, Toast.LENGTH_SHORT) 95 .show(); 96 return; 97 } 98 } 99 } 100 101 private void handleUnmount(Context context, Intent intent) { 102 final String fsUuid = intent.getStringExtra(VolumeRecord.EXTRA_FS_UUID); 103 if (TextUtils.isEmpty(fsUuid)) { 104 Log.e(TAG, "Missing fsUuid, not launching activity."); 105 return; 106 } 107 VolumeRecord volumeRecord = null; 108 try { 109 volumeRecord = mStorageManager.findRecordByUuid(fsUuid); 110 } catch (Exception e) { 111 Log.e(TAG, "Error finding volume record", e); 112 } 113 if (volumeRecord == null) { 114 return; 115 } 116 Log.d(TAG, "Found ejected volume: " + volumeRecord + " for FSUUID: " + fsUuid); 117 if (volumeRecord.getType() == VolumeInfo.TYPE_PRIVATE) { 118 final Intent i = NewStorageActivity.getMissingStorageLaunchIntent(context, fsUuid); 119 setPopupLaunchFlags(i); 120 context.startActivity(i); 121 } 122 } 123 124 private void handleSetupComplete(Context context) { 125 Log.d(TAG, "Scanning for storage post-setup"); 126 127 final List<DiskInfo> diskInfos = mStorageManager.getDisks(); 128 for (DiskInfo diskInfo : diskInfos) { 129 Log.d(TAG, "Scanning disk: " + diskInfo); 130 if (diskInfo.size <= 0) { 131 Log.d(TAG, "Disk ID " + diskInfo.id + " has no media"); 132 continue; 133 } 134 if (diskInfo.volumeCount != 0) { 135 Log.d(TAG, "Disk ID " + diskInfo.id + " has usable volumes, deferring"); 136 continue; 137 } 138 // No usable volumes, prompt the user to erase the disk 139 final Intent i = 140 NewStorageActivity.getNewStorageLaunchIntent(context, null, diskInfo.id); 141 setPopupLaunchFlags(i); 142 context.startActivity(i); 143 return; 144 } 145 146 final List<VolumeInfo> volumeInfos = mStorageManager.getVolumes(); 147 for (final VolumeInfo info : volumeInfos) { 148 final String uuid = info.getFsUuid(); 149 Log.d(TAG, "Scanning volume: " + info); 150 if (info.getType() != VolumeInfo.TYPE_PUBLIC || TextUtils.isEmpty(uuid)) { 151 continue; 152 } 153 final VolumeRecord record = mStorageManager.findRecordByUuid(uuid); 154 if (record.isInited() || record.isSnoozed()) { 155 continue; 156 } 157 final DiskInfo disk = info.getDisk(); 158 if (disk.isAdoptable()) { 159 final Intent i = NewStorageActivity.getNewStorageLaunchIntent(context, 160 info.getId(), disk.getId()); 161 setPopupLaunchFlags(i); 162 context.startActivity(i); 163 return; 164 } 165 } 166 } 167 168 private void setPopupLaunchFlags(Intent intent) { 169 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 170 } 171 } 172