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
17package com.android.settings.deviceinfo;
18
19import android.app.ActivityManager;
20import android.content.Context;
21import android.content.Intent;
22import android.net.Uri;
23import android.os.Bundle;
24import android.os.UserManager;
25import android.os.storage.DiskInfo;
26import android.os.storage.StorageEventListener;
27import android.os.storage.StorageManager;
28import android.os.storage.VolumeInfo;
29import android.os.storage.VolumeRecord;
30import android.preference.Preference;
31import android.preference.PreferenceScreen;
32import android.provider.DocumentsContract;
33import android.text.TextUtils;
34import android.text.format.Formatter;
35import android.text.format.Formatter.BytesResult;
36
37import com.android.internal.logging.MetricsLogger;
38import com.android.internal.util.Preconditions;
39import com.android.settings.R;
40import com.android.settings.SettingsPreferenceFragment;
41import com.android.settings.deviceinfo.StorageSettings.MountTask;
42import com.android.settings.deviceinfo.StorageSettings.UnmountTask;
43
44import java.io.File;
45import java.util.Objects;
46
47/**
48 * Panel showing summary and actions for a {@link VolumeInfo#TYPE_PUBLIC}
49 * storage volume.
50 */
51public class PublicVolumeSettings extends SettingsPreferenceFragment {
52    // TODO: disable unmount when providing over MTP/PTP
53
54    private StorageManager mStorageManager;
55
56    private String mVolumeId;
57    private VolumeInfo mVolume;
58    private DiskInfo mDisk;
59
60    private StorageSummaryPreference mSummary;
61
62    private Preference mMount;
63    private Preference mUnmount;
64    private Preference mFormatPublic;
65    private Preference mFormatPrivate;
66
67    private boolean mIsPermittedToAdopt;
68
69    private boolean isVolumeValid() {
70        return (mVolume != null) && (mVolume.getType() == VolumeInfo.TYPE_PUBLIC)
71                && mVolume.isMountedReadable();
72    }
73
74    @Override
75    protected int getMetricsCategory() {
76        return MetricsLogger.DEVICEINFO_STORAGE;
77    }
78
79    @Override
80    public void onCreate(Bundle icicle) {
81        super.onCreate(icicle);
82
83        final Context context = getActivity();
84
85        mIsPermittedToAdopt = UserManager.get(context).isAdminUser()
86                && !ActivityManager.isUserAMonkey();
87
88        mStorageManager = context.getSystemService(StorageManager.class);
89
90        if (DocumentsContract.ACTION_DOCUMENT_ROOT_SETTINGS.equals(
91                getActivity().getIntent().getAction())) {
92            final Uri rootUri = getActivity().getIntent().getData();
93            final String fsUuid = DocumentsContract.getRootId(rootUri);
94            mVolume = mStorageManager.findVolumeByUuid(fsUuid);
95        } else {
96            final String volId = getArguments().getString(VolumeInfo.EXTRA_VOLUME_ID);
97            mVolume = mStorageManager.findVolumeById(volId);
98        }
99
100        if (!isVolumeValid()) {
101            getActivity().finish();
102            return;
103        }
104
105        mDisk = mStorageManager.findDiskById(mVolume.getDiskId());
106        Preconditions.checkNotNull(mDisk);
107
108        mVolumeId = mVolume.getId();
109
110        addPreferencesFromResource(R.xml.device_info_storage_volume);
111        getPreferenceScreen().setOrderingAsAdded(true);
112
113        mSummary = new StorageSummaryPreference(context);
114
115        mMount = buildAction(R.string.storage_menu_mount);
116        mUnmount = buildAction(R.string.storage_menu_unmount);
117        mFormatPublic = buildAction(R.string.storage_menu_format);
118        if (mIsPermittedToAdopt) {
119            mFormatPrivate = buildAction(R.string.storage_menu_format_private);
120        }
121    }
122
123    public void update() {
124        if (!isVolumeValid()) {
125            getActivity().finish();
126            return;
127        }
128
129        getActivity().setTitle(mStorageManager.getBestVolumeDescription(mVolume));
130
131        final Context context = getActivity();
132        final PreferenceScreen screen = getPreferenceScreen();
133
134        screen.removeAll();
135
136        if (mVolume.isMountedReadable()) {
137            addPreference(mSummary);
138
139            final File file = mVolume.getPath();
140            final long totalBytes = file.getTotalSpace();
141            final long freeBytes = file.getFreeSpace();
142            final long usedBytes = totalBytes - freeBytes;
143
144            final BytesResult result = Formatter.formatBytes(getResources(), usedBytes, 0);
145            mSummary.setTitle(TextUtils.expandTemplate(getText(R.string.storage_size_large),
146                    result.value, result.units));
147            mSummary.setSummary(getString(R.string.storage_volume_used,
148                    Formatter.formatFileSize(context, totalBytes)));
149            mSummary.setPercent((int) ((usedBytes * 100) / totalBytes));
150        }
151
152        if (mVolume.getState() == VolumeInfo.STATE_UNMOUNTED) {
153            addPreference(mMount);
154        }
155        if (mVolume.isMountedReadable()) {
156            addPreference(mUnmount);
157        }
158        addPreference(mFormatPublic);
159        if (mDisk.isAdoptable() && mIsPermittedToAdopt) {
160            addPreference(mFormatPrivate);
161        }
162    }
163
164    private void addPreference(Preference pref) {
165        pref.setOrder(Preference.DEFAULT_ORDER);
166        getPreferenceScreen().addPreference(pref);
167    }
168
169    private Preference buildAction(int titleRes) {
170        final Preference pref = new Preference(getActivity());
171        pref.setTitle(titleRes);
172        return pref;
173    }
174
175    @Override
176    public void onResume() {
177        super.onResume();
178
179        // Refresh to verify that we haven't been formatted away
180        mVolume = mStorageManager.findVolumeById(mVolumeId);
181        if (!isVolumeValid()) {
182            getActivity().finish();
183            return;
184        }
185
186        mStorageManager.registerListener(mStorageListener);
187        update();
188    }
189
190    @Override
191    public void onPause() {
192        super.onPause();
193        mStorageManager.unregisterListener(mStorageListener);
194    }
195
196    @Override
197    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference pref) {
198        final Context context = getActivity();
199        if (pref == mMount) {
200            new MountTask(context, mVolume).execute();
201        } else if (pref == mUnmount) {
202            new UnmountTask(context, mVolume).execute();
203        } else if (pref == mFormatPublic) {
204            final Intent intent = new Intent(context, StorageWizardFormatConfirm.class);
205            intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
206            intent.putExtra(StorageWizardFormatConfirm.EXTRA_FORMAT_PRIVATE, false);
207            startActivity(intent);
208        } else if (pref == mFormatPrivate) {
209            final Intent intent = new Intent(context, StorageWizardFormatConfirm.class);
210            intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
211            intent.putExtra(StorageWizardFormatConfirm.EXTRA_FORMAT_PRIVATE, true);
212            startActivity(intent);
213        }
214
215        return super.onPreferenceTreeClick(preferenceScreen, pref);
216    }
217
218    private final StorageEventListener mStorageListener = new StorageEventListener() {
219        @Override
220        public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
221            if (Objects.equals(mVolume.getId(), vol.getId())) {
222                mVolume = vol;
223                update();
224            }
225        }
226
227        @Override
228        public void onVolumeRecordChanged(VolumeRecord rec) {
229            if (Objects.equals(mVolume.getFsUuid(), rec.getFsUuid())) {
230                mVolume = mStorageManager.findVolumeById(mVolumeId);
231                update();
232            }
233        }
234    };
235}
236