1104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne/*
2104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * Copyright (C) 2011 The Android Open Source Project
3104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne *
4104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * Licensed under the Apache License, Version 2.0 (the "License");
5104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * you may not use this file except in compliance with the License.
6104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * You may obtain a copy of the License at
7104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne *
8104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne *      http://www.apache.org/licenses/LICENSE-2.0
9104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne *
10104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * Unless required by applicable law or agreed to in writing, software
11104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * distributed under the License is distributed on an "AS IS" BASIS,
12104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * See the License for the specific language governing permissions and
14104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * limitations under the License.
15104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne */
16104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
17104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunnepackage com.android.settings.deviceinfo;
18104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
19da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkeyimport android.app.ActivityManager;
20104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.content.ComponentName;
21104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.content.Context;
22104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.content.Intent;
23104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.content.ServiceConnection;
24104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.content.pm.ApplicationInfo;
25104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.content.pm.IPackageStatsObserver;
26104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.content.pm.PackageManager;
27104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.content.pm.PackageStats;
28da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkeyimport android.content.pm.UserInfo;
29104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.os.Environment;
30fc76a78c458ac90d7e050ffc233cf9e32a2d9c0bJeff Sharkeyimport android.os.Environment.UserEnvironment;
31104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.os.Handler;
32104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.os.HandlerThread;
33104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.os.IBinder;
34104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.os.Looper;
35104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.os.Message;
3690c8b20ccfd8f2e877bfac7cf3e883631af7a3e3Jeff Sharkeyimport android.os.UserHandle;
37da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkeyimport android.os.UserManager;
38104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.os.storage.StorageVolume;
39104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.util.Log;
40da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkeyimport android.util.SparseLongArray;
41104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
42104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport com.android.internal.app.IMediaContainerService;
4390c8b20ccfd8f2e877bfac7cf3e883631af7a3e3Jeff Sharkeyimport com.google.android.collect.Maps;
44da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkeyimport com.google.common.collect.Sets;
45104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
46104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport java.io.File;
47104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport java.lang.ref.WeakReference;
48104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport java.util.ArrayList;
49104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport java.util.Collections;
5090c8b20ccfd8f2e877bfac7cf3e883631af7a3e3Jeff Sharkeyimport java.util.HashMap;
51104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport java.util.List;
52da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkeyimport java.util.Set;
53da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey
54da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkeyimport javax.annotation.concurrent.GuardedBy;
55104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
56104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne/**
57da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * Utility for measuring the disk usage of internal storage or a physical
58da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * {@link StorageVolume}. Connects with a remote {@link IMediaContainerService}
59da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * and delivers results to {@link MeasurementReceiver}.
60104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne */
61104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunnepublic class StorageMeasurement {
62104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    private static final String TAG = "StorageMeasurement";
63104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
64104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    private static final boolean LOCAL_LOGV = true;
65104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    static final boolean LOGV = LOCAL_LOGV && Log.isLoggable(TAG, Log.VERBOSE);
66104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
67da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    private static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
68104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
69da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    public static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
70da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            DEFAULT_CONTAINER_PACKAGE, "com.android.defcontainer.DefaultContainerService");
71104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
72da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    /** Media types to measure on external storage. */
73da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    private static final Set<String> sMeasureMediaTypes = Sets.newHashSet(
74da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            Environment.DIRECTORY_DCIM, Environment.DIRECTORY_MOVIES,
75da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            Environment.DIRECTORY_PICTURES, Environment.DIRECTORY_MUSIC,
76da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            Environment.DIRECTORY_ALARMS, Environment.DIRECTORY_NOTIFICATIONS,
77da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            Environment.DIRECTORY_RINGTONES, Environment.DIRECTORY_PODCASTS,
78da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            Environment.DIRECTORY_DOWNLOADS, Environment.DIRECTORY_ANDROID);
79104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
80da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    @GuardedBy("sInstances")
81da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    private static HashMap<StorageVolume, StorageMeasurement> sInstances = Maps.newHashMap();
82104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
83da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    /**
84da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey     * Obtain shared instance of {@link StorageMeasurement} for given physical
85da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey     * {@link StorageVolume}, or internal storage if {@code null}.
86da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey     */
87da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    public static StorageMeasurement getInstance(Context context, StorageVolume volume) {
88da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        synchronized (sInstances) {
89da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            StorageMeasurement value = sInstances.get(volume);
90da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            if (value == null) {
91da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                value = new StorageMeasurement(context.getApplicationContext(), volume);
92da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                sInstances.put(volume, value);
93da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            }
94da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            return value;
95da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        }
96da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    }
97104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
98da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    public static class MeasurementDetails {
99ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey        public long totalSize;
100ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey        public long availSize;
101ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey
102da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        /**
103da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * Total apps disk usage.
104da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * <p>
105da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * When measuring internal storage, this value includes the code size of
106da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * all apps (regardless of install status for current user), and
107da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * internal disk used by the current user's apps. When the device
108da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * emulates external storage, this value also includes emulated storage
109da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * used by the current user's apps.
110da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * <p>
111da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * When measuring a physical {@link StorageVolume}, this value includes
112da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * usage by all apps on that volume.
113da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         */
114da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        public long appsSize;
115104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
116da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        /**
117ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey         * Total cache disk usage by apps.
118ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey         */
119ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey        public long cacheSize;
120ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey
121ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey        /**
122da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * Total media disk usage, categorized by types such as
123da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * {@link Environment#DIRECTORY_MUSIC}.
124da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * <p>
125da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * When measuring internal storage, this reflects media on emulated
126da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * storage for the current user.
127da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * <p>
128da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * When measuring a physical {@link StorageVolume}, this reflects media
129da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * on that volume.
130da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         */
131da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        public HashMap<String, Long> mediaSize = Maps.newHashMap();
132104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
133da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        /**
134da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * Misc external disk usage for the current user, unaccounted in
135da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * {@link #mediaSize}.
136da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         */
137da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        public long miscSize;
138104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
139da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        /**
140da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * Total disk usage for users, which is only meaningful for emulated
141da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         * internal storage. Key is {@link UserHandle}.
142da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey         */
143da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        public SparseLongArray usersSize = new SparseLongArray();
144da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    }
145104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
146da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    public interface MeasurementReceiver {
147da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        public void updateApproximate(StorageMeasurement meas, long totalSize, long availSize);
148da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        public void updateDetails(StorageMeasurement meas, MeasurementDetails details);
149da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    }
150104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
151104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    private volatile WeakReference<MeasurementReceiver> mReceiver;
152104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
153da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    /** Physical volume being measured, or {@code null} for internal. */
154da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    private final StorageVolume mVolume;
155da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey
15690c8b20ccfd8f2e877bfac7cf3e883631af7a3e3Jeff Sharkey    private final boolean mIsInternal;
157da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    private final boolean mIsPrimary;
15890c8b20ccfd8f2e877bfac7cf3e883631af7a3e3Jeff Sharkey
159da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    private final MeasurementHandler mHandler;
160104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
161da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    private long mTotalSize;
162da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    private long mAvailSize;
163104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
164da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    List<FileInfo> mFileInfoForMisc;
165104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
166da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    private StorageMeasurement(Context context, StorageVolume volume) {
167da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        mVolume = volume;
16896c2f8c50865e823e710be4d92f1589f978f03c2Jeff Sharkey        mIsInternal = volume == null;
16996c2f8c50865e823e710be4d92f1589f978f03c2Jeff Sharkey        mIsPrimary = volume != null ? volume.isPrimary() : false;
170104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
171104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        // Start the thread that will measure the disk usage.
172104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        final HandlerThread handlerThread = new HandlerThread("MemoryMeasurement");
173104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        handlerThread.start();
174104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        mHandler = new MeasurementHandler(context, handlerThread.getLooper());
175104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    }
176104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
177104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    public void setReceiver(MeasurementReceiver receiver) {
178104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        if (mReceiver == null || mReceiver.get() == null) {
179104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            mReceiver = new WeakReference<MeasurementReceiver>(receiver);
180104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        }
181104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    }
182104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
183104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    public void measure() {
184104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        if (!mHandler.hasMessages(MeasurementHandler.MSG_MEASURE)) {
185104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            mHandler.sendEmptyMessage(MeasurementHandler.MSG_MEASURE);
186104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        }
187104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    }
188104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
189104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    public void cleanUp() {
190104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        mReceiver = null;
191104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        mHandler.removeMessages(MeasurementHandler.MSG_MEASURE);
192104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        mHandler.sendEmptyMessage(MeasurementHandler.MSG_DISCONNECT);
193104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    }
194104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
195104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    public void invalidate() {
196104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        mHandler.sendEmptyMessage(MeasurementHandler.MSG_INVALIDATE);
197104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    }
198104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
199104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    private void sendInternalApproximateUpdate() {
200104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        MeasurementReceiver receiver = (mReceiver != null) ? mReceiver.get() : null;
201104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        if (receiver == null) {
202104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            return;
203104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        }
204da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        receiver.updateApproximate(this, mTotalSize, mAvailSize);
205104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    }
206104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
207da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    private void sendExactUpdate(MeasurementDetails details) {
208104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        MeasurementReceiver receiver = (mReceiver != null) ? mReceiver.get() : null;
209104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        if (receiver == null) {
210104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            if (LOGV) {
211104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                Log.i(TAG, "measurements dropped because receiver is null! wasted effort");
212104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            }
213104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            return;
214104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        }
215da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        receiver.updateDetails(this, details);
216da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    }
217104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
218da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    private static class StatsObserver extends IPackageStatsObserver.Stub {
219da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        private final boolean mIsInternal;
220da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        private final MeasurementDetails mDetails;
221da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        private final int mCurrentUser;
222da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        private final Message mFinished;
223da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey
224da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        private int mRemaining;
225da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey
226da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        public StatsObserver(boolean isInternal, MeasurementDetails details, int currentUser,
227da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                Message finished, int remaining) {
228da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            mIsInternal = isInternal;
229da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            mDetails = details;
230da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            mCurrentUser = currentUser;
231da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            mFinished = finished;
232da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            mRemaining = remaining;
233da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        }
234104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
235da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        @Override
236da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        public void onGetStatsCompleted(PackageStats stats, boolean succeeded) {
237da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            synchronized (mDetails) {
238da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                if (succeeded) {
239da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                    addStatsLocked(stats);
240da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                }
241da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                if (--mRemaining == 0) {
242da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                    mFinished.sendToTarget();
243da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                }
244da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            }
245da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        }
246da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey
247da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        private void addStatsLocked(PackageStats stats) {
248da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            if (mIsInternal) {
249ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey                long codeSize = stats.codeSize;
250ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey                long dataSize = stats.dataSize;
251ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey                long cacheSize = stats.cacheSize;
252da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                if (Environment.isExternalStorageEmulated()) {
253ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey                    // Include emulated storage when measuring internal. OBB is
254ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey                    // shared on emulated storage, so treat as code.
255ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey                    codeSize += stats.externalCodeSize + stats.externalObbSize;
256ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey                    dataSize += stats.externalDataSize + stats.externalMediaSize;
257ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey                    cacheSize += stats.externalCacheSize;
258da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                }
259da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey
260ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey                // Count code and data for current user
261da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                if (stats.userHandle == mCurrentUser) {
262da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                    mDetails.appsSize += codeSize;
263da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                    mDetails.appsSize += dataSize;
264da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                }
265da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey
266ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey                // User summary only includes data (code is only counted once
267ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey                // for the current user)
268da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                addValue(mDetails.usersSize, stats.userHandle, dataSize);
269da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey
270ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey                // Include cache for all users
271ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey                mDetails.cacheSize += cacheSize;
272ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey
273da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            } else {
274da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                // Physical storage; only count external sizes
275ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey                mDetails.appsSize += stats.externalCodeSize + stats.externalDataSize
276ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey                        + stats.externalMediaSize + stats.externalObbSize;
277ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey                mDetails.cacheSize += stats.externalCacheSize;
278da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            }
279da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        }
280104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    }
281104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
282104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    private class MeasurementHandler extends Handler {
283104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        public static final int MSG_MEASURE = 1;
284104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        public static final int MSG_CONNECTED = 2;
285104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        public static final int MSG_DISCONNECT = 3;
286104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        public static final int MSG_COMPLETED = 4;
287104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        public static final int MSG_INVALIDATE = 5;
288104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
289104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        private Object mLock = new Object();
290104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
291104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        private IMediaContainerService mDefaultContainer;
292104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
293104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        private volatile boolean mBound = false;
294104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
295da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        private MeasurementDetails mCached;
296104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
297104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        private final WeakReference<Context> mContext;
298104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
299da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        private final ServiceConnection mDefContainerConn = new ServiceConnection() {
300da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            @Override
301104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            public void onServiceConnected(ComponentName name, IBinder service) {
302da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                final IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(
303da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                        service);
304104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                mDefaultContainer = imcs;
305104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                mBound = true;
306104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                sendMessage(obtainMessage(MSG_CONNECTED, imcs));
307104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            }
308104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
309da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            @Override
310104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            public void onServiceDisconnected(ComponentName name) {
311104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                mBound = false;
312104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                removeMessages(MSG_CONNECTED);
313104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            }
314104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        };
315104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
316104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        public MeasurementHandler(Context context, Looper looper) {
317104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            super(looper);
318104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            mContext = new WeakReference<Context>(context);
319104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        }
320104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
321104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        @Override
322104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        public void handleMessage(Message msg) {
323104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            switch (msg.what) {
324104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                case MSG_MEASURE: {
325da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                    if (mCached != null) {
326da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                        sendExactUpdate(mCached);
327104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                        break;
328104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                    }
329104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
330104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                    final Context context = (mContext != null) ? mContext.get() : null;
331104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                    if (context == null) {
332104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                        return;
333104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                    }
334104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
335104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                    synchronized (mLock) {
336104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                        if (mBound) {
337104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                            removeMessages(MSG_DISCONNECT);
338104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                            sendMessage(obtainMessage(MSG_CONNECTED, mDefaultContainer));
339104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                        } else {
340104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                            Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
341da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                            context.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE,
342da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                                    UserHandle.USER_OWNER);
343104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                        }
344104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                    }
345104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                    break;
346104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                }
347104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                case MSG_CONNECTED: {
348104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                    IMediaContainerService imcs = (IMediaContainerService) msg.obj;
34944dda2d7f52007d2ef33b9e9b9b9b1ec84c5582eJeff Sharkey                    measureApproximateStorage(imcs);
350104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                    measureExactStorage(imcs);
351104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                    break;
352104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                }
353104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                case MSG_DISCONNECT: {
354104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                    synchronized (mLock) {
355104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                        if (mBound) {
356104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                            final Context context = (mContext != null) ? mContext.get() : null;
357104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                            if (context == null) {
358104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                                return;
359104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                            }
360104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
361104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                            mBound = false;
362104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                            context.unbindService(mDefContainerConn);
363104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                        }
364104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                    }
365104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                    break;
366104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                }
367104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                case MSG_COMPLETED: {
368da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                    mCached = (MeasurementDetails) msg.obj;
369da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                    sendExactUpdate(mCached);
370104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                    break;
371104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                }
372104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                case MSG_INVALIDATE: {
373da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                    mCached = null;
374104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                    break;
375104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                }
376104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            }
377104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        }
378104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
37944dda2d7f52007d2ef33b9e9b9b9b1ec84c5582eJeff Sharkey        private void measureApproximateStorage(IMediaContainerService imcs) {
380da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            final String path = mVolume != null ? mVolume.getPath()
38144dda2d7f52007d2ef33b9e9b9b9b1ec84c5582eJeff Sharkey                    : Environment.getDataDirectory().getPath();
38244dda2d7f52007d2ef33b9e9b9b9b1ec84c5582eJeff Sharkey            try {
38344dda2d7f52007d2ef33b9e9b9b9b1ec84c5582eJeff Sharkey                final long[] stats = imcs.getFileSystemStats(path);
38444dda2d7f52007d2ef33b9e9b9b9b1ec84c5582eJeff Sharkey                mTotalSize = stats[0];
38544dda2d7f52007d2ef33b9e9b9b9b1ec84c5582eJeff Sharkey                mAvailSize = stats[1];
386fc76a78c458ac90d7e050ffc233cf9e32a2d9c0bJeff Sharkey            } catch (Exception e) {
38744dda2d7f52007d2ef33b9e9b9b9b1ec84c5582eJeff Sharkey                Log.w(TAG, "Problem in container service", e);
38844dda2d7f52007d2ef33b9e9b9b9b1ec84c5582eJeff Sharkey            }
389104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
390104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            sendInternalApproximateUpdate();
391104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        }
392104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
393104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        private void measureExactStorage(IMediaContainerService imcs) {
394da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            final Context context = mContext != null ? mContext.get() : null;
395104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            if (context == null) {
396104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                return;
397104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            }
398104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
399da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            final MeasurementDetails details = new MeasurementDetails();
400da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            final Message finished = obtainMessage(MSG_COMPLETED, details);
401da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey
402ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey            details.totalSize = mTotalSize;
403ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey            details.availSize = mAvailSize;
404ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey
405da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            final UserManager userManager = (UserManager) context.getSystemService(
406da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                    Context.USER_SERVICE);
407da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            final List<UserInfo> users = userManager.getUsers();
408da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey
409da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            final int currentUser = ActivityManager.getCurrentUser();
410da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            final UserEnvironment currentEnv = new UserEnvironment(currentUser);
411da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey
412da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            // Measure media types for emulated storage, or for primary physical
413da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            // external volume
414da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            final boolean measureMedia = (mIsInternal && Environment.isExternalStorageEmulated())
415da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                    || mIsPrimary;
416da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            if (measureMedia) {
417da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                for (String type : sMeasureMediaTypes) {
418da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                    final File path = currentEnv.getExternalStoragePublicDirectory(type);
419da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                    final long size = getDirectorySize(imcs, path);
420da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                    details.mediaSize.put(type, size);
421104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                }
422104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            }
423104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
424da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            // Measure misc files not counted under media
425da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            if (mIsInternal || mIsPrimary) {
426da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                final File path = mIsInternal ? currentEnv.getExternalStorageDirectory()
427da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                        : mVolume.getPathFile();
428da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                details.miscSize = measureMisc(imcs, path);
429104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            }
430104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
431da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            // Measure total emulated storage of all users; internal apps data
432da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            // will be spliced in later
433da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            for (UserInfo user : users) {
434da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                final UserEnvironment userEnv = new UserEnvironment(user.id);
435da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                final long size = getDirectorySize(imcs, userEnv.getExternalStorageDirectory());
436da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                addValue(details.usersSize, user.id, size);
437104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            }
438104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
439da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            // Measure all apps for all users
440da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            final PackageManager pm = context.getPackageManager();
441da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            if (mIsInternal || mIsPrimary) {
442da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                final List<ApplicationInfo> apps = pm.getInstalledApplications(
443da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                        PackageManager.GET_UNINSTALLED_PACKAGES
444da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                        | PackageManager.GET_DISABLED_COMPONENTS);
445104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
446da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                final int count = users.size() * apps.size();
447da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                final StatsObserver observer = new StatsObserver(
448da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                        mIsInternal, details, currentUser, finished, count);
449104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
450da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                for (UserInfo user : users) {
451da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                    for (ApplicationInfo app : apps) {
452da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                        pm.getPackageSizeInfo(app.packageName, user.id, observer);
453104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                    }
454104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                }
455104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
456104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            } else {
457da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                finished.sendToTarget();
458104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            }
459104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        }
460104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    }
461104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
462da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    private static long getDirectorySize(IMediaContainerService imcs, File path) {
463104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        try {
464da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            final long size = imcs.calculateDirectorySize(path.toString());
465da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            Log.d(TAG, "getDirectorySize(" + path + ") returned " + size);
466da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            return size;
467104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        } catch (Exception e) {
468da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            Log.w(TAG, "Could not read memory from default container service for " + path, e);
469104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            return 0;
470104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        }
471104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    }
472104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
473da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    private long measureMisc(IMediaContainerService imcs, File dir) {
474104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        mFileInfoForMisc = new ArrayList<FileInfo>();
475da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey
476da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        final File[] files = dir.listFiles();
477da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        if (files == null) return 0;
478da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey
479da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        // Get sizes of all top level nodes except the ones already computed
480104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        long counter = 0;
481da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        long miscSize = 0;
482da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey
483da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        for (File file : files) {
484da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            final String path = file.getAbsolutePath();
485da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            final String name = file.getName();
486da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            if (sMeasureMediaTypes.contains(name)) {
487104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                continue;
488104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            }
489da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey
490da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            if (file.isFile()) {
491da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                final long fileSize = file.length();
492104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                mFileInfoForMisc.add(new FileInfo(path, fileSize, counter++));
493da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                miscSize += fileSize;
494da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey            } else if (file.isDirectory()) {
495da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                final long dirSize = getDirectorySize(imcs, file);
496104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                mFileInfoForMisc.add(new FileInfo(path, dirSize, counter++));
497da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey                miscSize += dirSize;
498104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            } else {
499104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne                // Non directory, non file: not listed
500104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            }
501104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        }
502da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey
503104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        // sort the list of FileInfo objects collected above in descending order of their sizes
504104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        Collections.sort(mFileInfoForMisc);
505da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey
506da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        return miscSize;
507104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    }
508104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
509104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    static class FileInfo implements Comparable<FileInfo> {
510104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        final String mFileName;
511104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        final long mSize;
512104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        final long mId;
513104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
514104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        FileInfo(String fileName, long size, long id) {
515104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            mFileName = fileName;
516104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            mSize = size;
517104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            mId = id;
518104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        }
519104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
520104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        @Override
521104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        public int compareTo(FileInfo that) {
522104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            if (this == that || mSize == that.mSize) return 0;
523104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            else return (mSize < that.mSize) ? 1 : -1; // for descending sort
524104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        }
525104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne
526104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        @Override
527104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        public String toString() {
528104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne            return mFileName  + " : " + mSize + ", id:" + mId;
529104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne        }
530104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne    }
5314f734d9d590d0f75a60d744d97218eb54faa4330Gilles Debunne
532da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey    private static void addValue(SparseLongArray array, int key, long value) {
533da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey        array.put(key, array.get(key) + value);
5344f734d9d590d0f75a60d744d97218eb54faa4330Gilles Debunne    }
535104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne}
536