1 /*
2  * Copyright (C) 2015 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.net.Uri;
24 import android.os.Bundle;
25 import android.os.UserManager;
26 import android.os.storage.DiskInfo;
27 import android.os.storage.StorageEventListener;
28 import android.os.storage.StorageManager;
29 import android.os.storage.VolumeInfo;
30 import android.os.storage.VolumeRecord;
31 import android.provider.DocumentsContract;
32 import android.view.View;
33 import android.view.ViewGroup;
34 import android.widget.Button;
35 
36 import androidx.preference.Preference;
37 import androidx.preference.PreferenceScreen;
38 
39 import com.android.internal.util.Preconditions;
40 import com.android.settings.R;
41 import com.android.settings.SettingsPreferenceFragment;
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.widget.UsageProgressBarPreference;
46 
47 import java.io.File;
48 import java.util.Objects;
49 
50 /**
51  * Panel showing summary and actions for a {@link VolumeInfo#TYPE_PUBLIC}
52  * storage volume.
53  */
54 public class PublicVolumeSettings extends SettingsPreferenceFragment {
55     // TODO: disable unmount when providing over MTP/PTP
56 
57     private StorageManager mStorageManager;
58 
59     private String mVolumeId;
60     private VolumeInfo mVolume;
61     private final View.OnClickListener mUnmountListener = new View.OnClickListener() {
62         @Override
63         public void onClick(View v) {
64             new UnmountTask(getActivity(), mVolume).execute();
65         }
66     };
67     private DiskInfo mDisk;
68     private UsageProgressBarPreference mSummary;
69     private Preference mMount;
70     private Preference mFormatPublic;
71     private Button mUnmount;
72     private final StorageEventListener mStorageListener = new StorageEventListener() {
73         @Override
74         public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
75             if (Objects.equals(mVolume.getId(), vol.getId())) {
76                 mVolume = vol;
77                 update();
78             }
79         }
80 
81         @Override
82         public void onVolumeRecordChanged(VolumeRecord rec) {
83             if (Objects.equals(mVolume.getFsUuid(), rec.getFsUuid())) {
84                 mVolume = mStorageManager.findVolumeById(mVolumeId);
85                 update();
86             }
87         }
88     };
89     private boolean mIsPermittedToAdopt;
90 
isVolumeValid()91     private boolean isVolumeValid() {
92         return (mVolume != null) && (mVolume.getType() == VolumeInfo.TYPE_PUBLIC)
93                 && mVolume.isMountedReadable();
94     }
95 
96     @Override
getMetricsCategory()97     public int getMetricsCategory() {
98         return SettingsEnums.PUBLIC_VOLUME_SETTINGS;
99     }
100 
101     @Override
onCreate(Bundle icicle)102     public void onCreate(Bundle icicle) {
103         super.onCreate(icicle);
104 
105         final Context context = getActivity();
106 
107         mIsPermittedToAdopt = UserManager.get(context).isAdminUser()
108                 && !ActivityManager.isUserAMonkey();
109 
110         mStorageManager = context.getSystemService(StorageManager.class);
111 
112         if (DocumentsContract.ACTION_DOCUMENT_ROOT_SETTINGS.equals(
113                 getActivity().getIntent().getAction())) {
114             final Uri rootUri = getActivity().getIntent().getData();
115             final String fsUuid = DocumentsContract.getRootId(rootUri);
116             mVolume = mStorageManager.findVolumeByUuid(fsUuid);
117         } else {
118             final String volId = getArguments().getString(VolumeInfo.EXTRA_VOLUME_ID);
119             if (volId != null) {
120                 mVolume = mStorageManager.findVolumeById(volId);
121             }
122         }
123 
124         if (!isVolumeValid()) {
125             getActivity().finish();
126             return;
127         }
128 
129         mDisk = mStorageManager.findDiskById(mVolume.getDiskId());
130         Preconditions.checkNotNull(mDisk);
131 
132         mVolumeId = mVolume.getId();
133 
134         addPreferencesFromResource(R.xml.device_info_storage_volume);
135         getPreferenceScreen().setOrderingAsAdded(true);
136 
137         mSummary = new UsageProgressBarPreference(getPrefContext());
138 
139         mMount = buildAction(R.string.storage_menu_mount);
140         mUnmount = new Button(getActivity());
141         mUnmount.setText(R.string.storage_menu_unmount);
142         mUnmount.setOnClickListener(mUnmountListener);
143         mFormatPublic = buildAction(R.string.storage_menu_format_option);
144     }
145 
146     @Override
onActivityCreated(Bundle savedInstanceState)147     public void onActivityCreated(Bundle savedInstanceState) {
148         super.onActivityCreated(savedInstanceState);
149 
150         // If the volume isn't valid, we are not scaffolded to set up a view.
151         if (!isVolumeValid()) {
152             return;
153         }
154 
155         final ViewGroup container = getActivity().findViewById(R.id.container_material);
156         container.addView(mUnmount, new ViewGroup.LayoutParams(
157                 ViewGroup.LayoutParams.MATCH_PARENT,
158                 ViewGroup.LayoutParams.WRAP_CONTENT));
159     }
160 
update()161     public void update() {
162         if (!isVolumeValid()) {
163             getActivity().finish();
164             return;
165         }
166 
167         getActivity().setTitle(mStorageManager.getBestVolumeDescription(mVolume));
168 
169         final Context context = getActivity();
170         final PreferenceScreen screen = getPreferenceScreen();
171 
172         screen.removeAll();
173 
174         if (mVolume.isMountedReadable()) {
175             addPreference(mSummary);
176 
177             final File file = mVolume.getPath();
178             final long totalBytes = file.getTotalSpace();
179             final long freeBytes = file.getFreeSpace();
180             final long usedBytes = totalBytes - freeBytes;
181 
182             mSummary.setUsageSummary(StorageUtils.getStorageSummary(
183                     context, R.string.storage_usage_summary, usedBytes));
184             mSummary.setTotalSummary(StorageUtils.getStorageSummary(
185                     context, R.string.storage_total_summary, totalBytes));
186             mSummary.setPercent(usedBytes, totalBytes);
187         }
188 
189         if (mVolume.getState() == VolumeInfo.STATE_UNMOUNTED) {
190             addPreference(mMount);
191         }
192         if (!mVolume.isMountedReadable()) {
193             mUnmount.setVisibility(View.GONE);
194         }
195         addPreference(mFormatPublic);
196     }
197 
addPreference(Preference pref)198     private void addPreference(Preference pref) {
199         pref.setOrder(Preference.DEFAULT_ORDER);
200         getPreferenceScreen().addPreference(pref);
201     }
202 
buildAction(int titleRes)203     private Preference buildAction(int titleRes) {
204         final Preference pref = new Preference(getPrefContext());
205         pref.setTitle(titleRes);
206         return pref;
207     }
208 
209     @Override
onResume()210     public void onResume() {
211         super.onResume();
212 
213         // Refresh to verify that we haven't been formatted away
214         mVolume = mStorageManager.findVolumeById(mVolumeId);
215         if (!isVolumeValid()) {
216             getActivity().finish();
217             return;
218         }
219 
220         mStorageManager.registerListener(mStorageListener);
221         update();
222     }
223 
224     @Override
onPause()225     public void onPause() {
226         super.onPause();
227         mStorageManager.unregisterListener(mStorageListener);
228     }
229 
230     @Override
onPreferenceTreeClick(Preference pref)231     public boolean onPreferenceTreeClick(Preference pref) {
232         final Intent intent = new Intent(getActivity(), StorageWizardInit.class);
233         intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mVolume.getId());
234         if (pref == mMount) {
235             new MountTask(getActivity(), mVolume).execute();
236         } else if (pref == mFormatPublic) {
237             startActivity(intent);
238         }
239 
240         return super.onPreferenceTreeClick(pref);
241     }
242 }