AppStorageSettings.java revision 08703c8bb19b518214bc352199bd46baab597547
1cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk/*
2cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk * Copyright (C) 2015 The Android Open Source Project
3cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk *
4cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk * Licensed under the Apache License, Version 2.0 (the "License");
5cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk * you may not use this file except in compliance with the License.
6cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk * You may obtain a copy of the License at
7cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk *
8cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk *      http://www.apache.org/licenses/LICENSE-2.0
9cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk *
10cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk * Unless required by applicable law or agreed to in writing, software
11cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk * distributed under the License is distributed on an "AS IS" BASIS,
12cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk * See the License for the specific language governing permissions and
14cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk * limitations under the License.
15cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk */
16cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
17cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkpackage com.android.settings.applications;
18cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
19cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.app.ActivityManager;
20cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.app.AlertDialog;
2116634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkeyimport android.app.AppGlobals;
22cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.Context;
23cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.DialogInterface;
24cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.Intent;
2508703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport android.content.UriPermission;
26cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.pm.ApplicationInfo;
27cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.pm.IPackageDataObserver;
2808703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport android.content.pm.PackageManager;
2908703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport android.content.pm.ProviderInfo;
30cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.os.Bundle;
31cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.os.Environment;
32cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.os.Handler;
33cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.os.Message;
3416634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkeyimport android.os.RemoteException;
359e9f7d11162df92bc430002423a281e22176de41Jeff Sharkeyimport android.os.UserHandle;
361f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport android.os.storage.StorageManager;
371f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport android.os.storage.VolumeInfo;
3839b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.support.v7.preference.Preference;
3939b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.support.v7.preference.PreferenceCategory;
40cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.text.format.Formatter;
41cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.util.Log;
4208703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport android.util.MutableInt;
43cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.view.View;
44cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.view.View.OnClickListener;
45cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.widget.Button;
46cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
478a963babe2e36b7a41f77b8d2598c97658196e58Chris Wrenimport com.android.internal.logging.MetricsLogger;
48cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport com.android.settings.R;
49cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport com.android.settings.Utils;
501f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport com.android.settings.deviceinfo.StorageWizardMoveConfirm;
5167cd6ab93a526fe65877743e458590f4e6f187eeTony Mantlerimport com.android.settingslib.applications.ApplicationsState;
5267cd6ab93a526fe65877743e458590f4e6f187eeTony Mantlerimport com.android.settingslib.applications.ApplicationsState.AppEntry;
5367cd6ab93a526fe65877743e458590f4e6f187eeTony Mantlerimport com.android.settingslib.applications.ApplicationsState.Callbacks;
541f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
5508703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport java.util.ArrayList;
561f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport java.util.Collections;
571f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport java.util.List;
5808703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport java.util.Map;
591f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport java.util.Objects;
6008703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport java.util.TreeMap;
61cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
6260a09ea2388db01a661beeb9995a7ecf770a4200Jason Monkpublic class AppStorageSettings extends AppInfoWithHeader
63e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        implements OnClickListener, Callbacks, DialogInterface.OnClickListener {
64588a0881c13d8ed63ba67b3145254c22211a2019Jason Monk    private static final String TAG = AppStorageSettings.class.getSimpleName();
65cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
66cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    //internal constants used in Handler
67cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int OP_SUCCESSFUL = 1;
68cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int OP_FAILED = 2;
69cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int MSG_CLEAR_USER_DATA = 1;
70cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int MSG_CLEAR_CACHE = 3;
71cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
72cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    // invalid size value used initially and also when size retrieval through PackageManager
73cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    // fails for whatever reason
74cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int SIZE_INVALID = -1;
75cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
76cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    // Result code identifiers
77cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    public static final int REQUEST_MANAGE_SPACE = 2;
78cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
79cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int DLG_CLEAR_DATA = DLG_BASE + 1;
80cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 2;
81cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
82e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private static final String KEY_STORAGE_USED = "storage_used";
83e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private static final String KEY_CHANGE_STORAGE = "change_storage_button";
84bd45c3cbe0ccb9d5a1ebeabccda1e803d613e729Jason Monk    private static final String KEY_STORAGE_SPACE = "storage_space";
85c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_STORAGE_CATEGORY = "storage_category";
8660a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk
87c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_TOTAL_SIZE = "total_size";
88c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_APP_SIZE = "app_size";
89c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_EXTERNAL_CODE_SIZE = "external_code_size";
90c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_DATA_SIZE = "data_size";
91c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_EXTERNAL_DATA_SIZE = "external_data_size";
92c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_CACHE_SIZE = "cache_size";
93c27f9e179adef2061e0000385f350874a7772c4eJason Monk
94c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_CLEAR_DATA = "clear_data_button";
95c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_CLEAR_CACHE = "clear_cache_button";
96c27f9e179adef2061e0000385f350874a7772c4eJason Monk
9708703c8bb19b518214bc352199bd46baab597547Felipe Leme    private static final String KEY_URI_CATEGORY = "uri_category";
9808703c8bb19b518214bc352199bd46baab597547Felipe Leme    private static final String KEY_CLEAR_URI = "clear_uri_button";
9908703c8bb19b518214bc352199bd46baab597547Felipe Leme
100c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private Preference mTotalSize;
101c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private Preference mAppSize;
102c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private Preference mDataSize;
103c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private Preference mExternalCodeSize;
104c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private Preference mExternalDataSize;
105cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
106cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    // Views related to cache info
107c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private Preference mCacheSize;
108cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private Button mClearDataButton;
109cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private Button mClearCacheButton;
11060a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk
111e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private Preference mStorageUsed;
112e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private Button mChangeStorageButton;
113cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
11408703c8bb19b518214bc352199bd46baab597547Felipe Leme    // Views related to URI permissions
11508703c8bb19b518214bc352199bd46baab597547Felipe Leme    private Button mClearUriButton;
11608703c8bb19b518214bc352199bd46baab597547Felipe Leme    private LayoutPreference mClearUri;
11708703c8bb19b518214bc352199bd46baab597547Felipe Leme    private PreferenceCategory mUri;
11808703c8bb19b518214bc352199bd46baab597547Felipe Leme
119cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private boolean mCanClearData = true;
120cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private boolean mHaveSizes = false;
121cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
122cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private long mLastCodeSize = -1;
123cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private long mLastDataSize = -1;
124cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private long mLastExternalCodeSize = -1;
125cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private long mLastExternalDataSize = -1;
126cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private long mLastCacheSize = -1;
127cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private long mLastTotalSize = -1;
128cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
129cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private ClearCacheObserver mClearCacheObserver;
130cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private ClearUserDataObserver mClearDataObserver;
131cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
132cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    // Resource strings
133cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private CharSequence mInvalidSizeStr;
134cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private CharSequence mComputingStr;
135cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
136e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private VolumeInfo[] mCandidates;
137e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private AlertDialog.Builder mDialogBuilder;
138e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk
139cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
140cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    public void onCreate(Bundle savedInstanceState) {
141cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        super.onCreate(savedInstanceState);
142cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
14360a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk        addPreferencesFromResource(R.xml.app_storage_settings);
14460a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk        setupViews();
145cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
146cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
147ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk    @Override
148ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk    public void onResume() {
149ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk        super.onResume();
150ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk        mState.requestSize(mPackageName, mUserId);
151ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk    }
152ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk
15360a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk    private void setupViews() {
154cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        mComputingStr = getActivity().getText(R.string.computing_size);
155cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        mInvalidSizeStr = getActivity().getText(R.string.invalid_size_value);
156cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
157cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        // Set default values on sizes
158c27f9e179adef2061e0000385f350874a7772c4eJason Monk        mTotalSize = findPreference(KEY_TOTAL_SIZE);
159c27f9e179adef2061e0000385f350874a7772c4eJason Monk        mAppSize =  findPreference(KEY_APP_SIZE);
160c27f9e179adef2061e0000385f350874a7772c4eJason Monk        mDataSize =  findPreference(KEY_DATA_SIZE);
161c27f9e179adef2061e0000385f350874a7772c4eJason Monk        mExternalCodeSize = findPreference(KEY_EXTERNAL_CODE_SIZE);
162c27f9e179adef2061e0000385f350874a7772c4eJason Monk        mExternalDataSize = findPreference(KEY_EXTERNAL_DATA_SIZE);
163cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
164cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (Environment.isExternalStorageEmulated()) {
165c27f9e179adef2061e0000385f350874a7772c4eJason Monk            PreferenceCategory category = (PreferenceCategory) findPreference(KEY_STORAGE_CATEGORY);
166c27f9e179adef2061e0000385f350874a7772c4eJason Monk            category.removePreference(mExternalCodeSize);
167c27f9e179adef2061e0000385f350874a7772c4eJason Monk            category.removePreference(mExternalDataSize);
168cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
169c27f9e179adef2061e0000385f350874a7772c4eJason Monk        mClearDataButton = (Button) ((LayoutPreference) findPreference(KEY_CLEAR_DATA))
17060a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk                .findViewById(R.id.button);
171cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
172e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mStorageUsed = findPreference(KEY_STORAGE_USED);
173e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mChangeStorageButton = (Button) ((LayoutPreference) findPreference(KEY_CHANGE_STORAGE))
174e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                .findViewById(R.id.button);
175e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mChangeStorageButton.setText(R.string.change);
176e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mChangeStorageButton.setOnClickListener(this);
177cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
178cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        // Cache section
179c27f9e179adef2061e0000385f350874a7772c4eJason Monk        mCacheSize = findPreference(KEY_CACHE_SIZE);
180c27f9e179adef2061e0000385f350874a7772c4eJason Monk        mClearCacheButton = (Button) ((LayoutPreference) findPreference(KEY_CLEAR_CACHE))
18160a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk                .findViewById(R.id.button);
18260a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk        mClearCacheButton.setText(R.string.clear_cache_btn_text);
18308703c8bb19b518214bc352199bd46baab597547Felipe Leme
18408703c8bb19b518214bc352199bd46baab597547Felipe Leme        // URI permissions section
18508703c8bb19b518214bc352199bd46baab597547Felipe Leme        mUri = (PreferenceCategory) findPreference(KEY_URI_CATEGORY);
18608703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUri = (LayoutPreference) mUri.findPreference(KEY_CLEAR_URI);
18708703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUriButton = (Button) mClearUri.findViewById(R.id.button);
18808703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUriButton.setText(R.string.clear_uri_btn_text);
18908703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUriButton.setOnClickListener(this);
190cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
191cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
192cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
193cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    public void onClick(View v) {
194cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (v == mClearCacheButton) {
195cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            // Lazy initialization of observer
196cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            if (mClearCacheObserver == null) {
197cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mClearCacheObserver = new ClearCacheObserver();
198cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
199cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mPm.deleteApplicationCacheFiles(mPackageName, mClearCacheObserver);
200e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        } else if (v == mClearDataButton) {
201cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            if (mAppEntry.info.manageSpaceActivityName != null) {
202cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                if (!Utils.isMonkeyRunning()) {
203cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    Intent intent = new Intent(Intent.ACTION_DEFAULT);
204cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    intent.setClassName(mAppEntry.info.packageName,
205cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            mAppEntry.info.manageSpaceActivityName);
206cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    startActivityForResult(intent, REQUEST_MANAGE_SPACE);
207cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                }
208cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            } else {
209cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                showDialogInner(DLG_CLEAR_DATA, 0);
210cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
21116634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey        } else if (v == mChangeStorageButton && mDialogBuilder != null && !isMoveInProgress()) {
212e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            mDialogBuilder.show();
21308703c8bb19b518214bc352199bd46baab597547Felipe Leme        } else if (v == mClearUriButton) {
21408703c8bb19b518214bc352199bd46baab597547Felipe Leme            clearUriPermissions();
21560a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk        }
21660a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk    }
21760a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk
21816634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey    private boolean isMoveInProgress() {
21916634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey        try {
22016634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey            // TODO: define a cleaner API for this
2219e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey            AppGlobals.getPackageManager().checkPackageStartable(mPackageName,
2229e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey                    UserHandle.myUserId());
22316634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey            return false;
2249e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey        } catch (RemoteException | SecurityException e) {
2259e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey            return true;
22616634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey        }
22716634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey    }
22816634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey
22960a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk    @Override
230e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    public void onClick(DialogInterface dialog, int which) {
2311f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final Context context = getActivity();
2321f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
2331f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        // If not current volume, kick off move wizard
234e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        final VolumeInfo targetVol = mCandidates[which];
235954d8dad5e395544f95ca211466bcc7195d31877Jeff Sharkey        final VolumeInfo currentVol = context.getPackageManager().getPackageCurrentVolume(
2361f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey                mAppEntry.info);
2371f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        if (!Objects.equals(targetVol, currentVol)) {
2381f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey            final Intent intent = new Intent(context, StorageWizardMoveConfirm.class);
2391f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey            intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, targetVol.getId());
2401f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey            intent.putExtra(Intent.EXTRA_PACKAGE_NAME, mAppEntry.info.packageName);
2411f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey            startActivity(intent);
242cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
243e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        dialog.dismiss();
244cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
245cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
246cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private String getSizeStr(long size) {
247cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (size == SIZE_INVALID) {
248cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            return mInvalidSizeStr.toString();
249cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
250cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        return Formatter.formatFileSize(getActivity(), size);
251cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
252cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
253cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private void refreshSizeInfo() {
254cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (mAppEntry.size == ApplicationsState.SIZE_INVALID
255cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                || mAppEntry.size == ApplicationsState.SIZE_UNKNOWN) {
256cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mLastCodeSize = mLastDataSize = mLastCacheSize = mLastTotalSize = -1;
257cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            if (!mHaveSizes) {
258c27f9e179adef2061e0000385f350874a7772c4eJason Monk                mAppSize.setSummary(mComputingStr);
259c27f9e179adef2061e0000385f350874a7772c4eJason Monk                mDataSize.setSummary(mComputingStr);
260c27f9e179adef2061e0000385f350874a7772c4eJason Monk                mCacheSize.setSummary(mComputingStr);
261c27f9e179adef2061e0000385f350874a7772c4eJason Monk                mTotalSize.setSummary(mComputingStr);
262cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
263cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataButton.setEnabled(false);
264cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearCacheButton.setEnabled(false);
265cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        } else {
266cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mHaveSizes = true;
267cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            long codeSize = mAppEntry.codeSize;
268cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            long dataSize = mAppEntry.dataSize;
269cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            if (Environment.isExternalStorageEmulated()) {
270cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                codeSize += mAppEntry.externalCodeSize;
271cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                dataSize +=  mAppEntry.externalDataSize;
272cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            } else {
273cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                if (mLastExternalCodeSize != mAppEntry.externalCodeSize) {
274cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    mLastExternalCodeSize = mAppEntry.externalCodeSize;
275c27f9e179adef2061e0000385f350874a7772c4eJason Monk                    mExternalCodeSize.setSummary(getSizeStr(mAppEntry.externalCodeSize));
276cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                }
277cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                if (mLastExternalDataSize !=  mAppEntry.externalDataSize) {
278cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    mLastExternalDataSize =  mAppEntry.externalDataSize;
279c27f9e179adef2061e0000385f350874a7772c4eJason Monk                    mExternalDataSize.setSummary(getSizeStr( mAppEntry.externalDataSize));
280cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                }
281cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
282cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            if (mLastCodeSize != codeSize) {
283cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mLastCodeSize = codeSize;
284c27f9e179adef2061e0000385f350874a7772c4eJason Monk                mAppSize.setSummary(getSizeStr(codeSize));
285cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
286cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            if (mLastDataSize != dataSize) {
287cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mLastDataSize = dataSize;
288c27f9e179adef2061e0000385f350874a7772c4eJason Monk                mDataSize.setSummary(getSizeStr(dataSize));
289cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
290cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            long cacheSize = mAppEntry.cacheSize + mAppEntry.externalCacheSize;
291cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            if (mLastCacheSize != cacheSize) {
292cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mLastCacheSize = cacheSize;
293c27f9e179adef2061e0000385f350874a7772c4eJason Monk                mCacheSize.setSummary(getSizeStr(cacheSize));
294cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
295cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            if (mLastTotalSize != mAppEntry.size) {
296cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mLastTotalSize = mAppEntry.size;
297c27f9e179adef2061e0000385f350874a7772c4eJason Monk                mTotalSize.setSummary(getSizeStr(mAppEntry.size));
298cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
299cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
300cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            if ((mAppEntry.dataSize+ mAppEntry.externalDataSize) <= 0 || !mCanClearData) {
301cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mClearDataButton.setEnabled(false);
302cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            } else {
303cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mClearDataButton.setEnabled(true);
304cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mClearDataButton.setOnClickListener(this);
305cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
306cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            if (cacheSize <= 0) {
307cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mClearCacheButton.setEnabled(false);
308cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            } else {
309cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mClearCacheButton.setEnabled(true);
310cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mClearCacheButton.setOnClickListener(this);
311cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
312cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
313cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (mAppControlRestricted) {
314cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearCacheButton.setEnabled(false);
315cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataButton.setEnabled(false);
316cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
317cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
318cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
319cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
320cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    protected boolean refreshUi() {
321cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        retrieveAppEntry();
3229a1c0dce7a496f51087cf0497b931a31c64b0a65Julia Reynolds        if (mAppEntry == null) {
3239a1c0dce7a496f51087cf0497b931a31c64b0a65Julia Reynolds            return false;
3249a1c0dce7a496f51087cf0497b931a31c64b0a65Julia Reynolds        }
325cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        refreshSizeInfo();
32608703c8bb19b518214bc352199bd46baab597547Felipe Leme        refreshGrantedUriPermissions();
3271f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
3281f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final VolumeInfo currentVol = getActivity().getPackageManager()
329954d8dad5e395544f95ca211466bcc7195d31877Jeff Sharkey                .getPackageCurrentVolume(mAppEntry.info);
330e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        final StorageManager storage = getContext().getSystemService(StorageManager.class);
331e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mStorageUsed.setSummary(storage.getBestVolumeDescription(currentVol));
332e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk
333e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        refreshButtons();
3341f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
335cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        return true;
336cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
337cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
338cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private void refreshButtons() {
339e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        initMoveDialog();
3401f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        initDataButtons();
341cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
342cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
343cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private void initDataButtons() {
344cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        // If the app doesn't have its own space management UI
345cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        // And it's a system app that doesn't allow clearing user data or is an active admin
346cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        // Then disable the Clear Data button.
347cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (mAppEntry.info.manageSpaceActivityName == null
348cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                && ((mAppEntry.info.flags&(ApplicationInfo.FLAG_SYSTEM
349cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        | ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA))
350cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        == ApplicationInfo.FLAG_SYSTEM
351cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        || mDpm.packageHasActiveAdmins(mPackageName))) {
352cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataButton.setText(R.string.clear_user_data_text);
353cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataButton.setEnabled(false);
354cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mCanClearData = false;
355cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        } else {
356cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            if (mAppEntry.info.manageSpaceActivityName != null) {
357cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mClearDataButton.setText(R.string.manage_space_text);
358cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            } else {
359cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mClearDataButton.setText(R.string.clear_user_data_text);
360cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
361cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataButton.setOnClickListener(this);
362cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
363cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
364cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (mAppControlRestricted) {
365cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataButton.setEnabled(false);
366cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
367cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
368cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
369e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private void initMoveDialog() {
3701f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final Context context = getActivity();
3711f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final StorageManager storage = context.getSystemService(StorageManager.class);
3721f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
3731f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final List<VolumeInfo> candidates = context.getPackageManager()
374954d8dad5e395544f95ca211466bcc7195d31877Jeff Sharkey                .getPackageCandidateVolumes(mAppEntry.info);
375c27f9e179adef2061e0000385f350874a7772c4eJason Monk        if (candidates.size() > 1) {
376c27f9e179adef2061e0000385f350874a7772c4eJason Monk            Collections.sort(candidates, VolumeInfo.getDescriptionComparator());
3771f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
378e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            CharSequence[] labels = new CharSequence[candidates.size()];
379e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            int current = -1;
380e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            for (int i = 0; i < candidates.size(); i++) {
381e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                final String volDescrip = storage.getBestVolumeDescription(candidates.get(i));
382e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                if (Objects.equals(volDescrip, mStorageUsed.getSummary())) {
383e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                    current = i;
384e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                }
385e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                labels[i] = volDescrip;
386c27f9e179adef2061e0000385f350874a7772c4eJason Monk            }
387e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            mCandidates = candidates.toArray(new VolumeInfo[candidates.size()]);
388e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            mDialogBuilder = new AlertDialog.Builder(getContext())
389e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                    .setTitle(R.string.change_storage)
390e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                    .setSingleChoiceItems(labels, current, this)
391e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                    .setNegativeButton(R.string.cancel, null);
392c27f9e179adef2061e0000385f350874a7772c4eJason Monk        } else {
393e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            removePreference(KEY_STORAGE_USED);
394e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            removePreference(KEY_CHANGE_STORAGE);
395bd45c3cbe0ccb9d5a1ebeabccda1e803d613e729Jason Monk            removePreference(KEY_STORAGE_SPACE);
396cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
397cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
398cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
399cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    /*
400cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     * Private method to initiate clearing user data when the user clicks the clear data
401cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     * button for a system package
402cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     */
403cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private void initiateClearUserData() {
404cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        mClearDataButton.setEnabled(false);
405cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        // Invoke uninstall or clear user data based on sysPackage
406cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        String packageName = mAppEntry.info.packageName;
407cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        Log.i(TAG, "Clearing user data for package : " + packageName);
408cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (mClearDataObserver == null) {
409cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataObserver = new ClearUserDataObserver();
410cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
411cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        ActivityManager am = (ActivityManager)
412cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                getActivity().getSystemService(Context.ACTIVITY_SERVICE);
413cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        boolean res = am.clearApplicationUserData(packageName, mClearDataObserver);
414cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (!res) {
415cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            // Clearing data failed for some obscure reason. Just log error for now
416cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            Log.i(TAG, "Couldnt clear application user data for package:"+packageName);
417cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            showDialogInner(DLG_CANNOT_CLEAR_DATA, 0);
418cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        } else {
419cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataButton.setText(R.string.recompute_size);
420cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
421cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
422cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
423cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    /*
424cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     * Private method to handle clear message notification from observer when
425cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     * the async operation from PackageManager is complete
426cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     */
427cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private void processClearMsg(Message msg) {
428cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        int result = msg.arg1;
429cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        String packageName = mAppEntry.info.packageName;
430cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        mClearDataButton.setText(R.string.clear_user_data_text);
43160a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk        if (result == OP_SUCCESSFUL) {
432cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            Log.i(TAG, "Cleared user data for package : "+packageName);
43307025891683aef83d850b0a91b37aa75b11ce33cJason Monk            mState.requestSize(mPackageName, mUserId);
434cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        } else {
435cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataButton.setEnabled(true);
436cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
437cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
438cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
43908703c8bb19b518214bc352199bd46baab597547Felipe Leme    private void refreshGrantedUriPermissions() {
44008703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Clear UI first (in case the activity has been resumed)
44108703c8bb19b518214bc352199bd46baab597547Felipe Leme        removeUriPermissionsFromUi();
44208703c8bb19b518214bc352199bd46baab597547Felipe Leme
44308703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Gets all URI permissions from am.
44408703c8bb19b518214bc352199bd46baab597547Felipe Leme        ActivityManager am = (ActivityManager) getActivity().getSystemService(
44508703c8bb19b518214bc352199bd46baab597547Felipe Leme                Context.ACTIVITY_SERVICE);
44608703c8bb19b518214bc352199bd46baab597547Felipe Leme        List<UriPermission> perms =
44708703c8bb19b518214bc352199bd46baab597547Felipe Leme                am.getGrantedUriPermissions(mAppEntry.info.packageName).getList();
44808703c8bb19b518214bc352199bd46baab597547Felipe Leme
44908703c8bb19b518214bc352199bd46baab597547Felipe Leme        if (perms.isEmpty()) {
45008703c8bb19b518214bc352199bd46baab597547Felipe Leme            mClearUriButton.setVisibility(View.GONE);
45108703c8bb19b518214bc352199bd46baab597547Felipe Leme            return;
45208703c8bb19b518214bc352199bd46baab597547Felipe Leme        }
45308703c8bb19b518214bc352199bd46baab597547Felipe Leme
45408703c8bb19b518214bc352199bd46baab597547Felipe Leme        PackageManager pm = getActivity().getPackageManager();
45508703c8bb19b518214bc352199bd46baab597547Felipe Leme
45608703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Group number of URIs by app.
45708703c8bb19b518214bc352199bd46baab597547Felipe Leme        Map<CharSequence, MutableInt> uriCounters = new TreeMap<>();
45808703c8bb19b518214bc352199bd46baab597547Felipe Leme        for (UriPermission perm : perms) {
45908703c8bb19b518214bc352199bd46baab597547Felipe Leme            String authority = perm.getUri().getAuthority();
46008703c8bb19b518214bc352199bd46baab597547Felipe Leme            ProviderInfo provider = pm.resolveContentProvider(authority, 0);
46108703c8bb19b518214bc352199bd46baab597547Felipe Leme            CharSequence app = provider.applicationInfo.loadLabel(pm);
46208703c8bb19b518214bc352199bd46baab597547Felipe Leme            MutableInt count = uriCounters.get(app);
46308703c8bb19b518214bc352199bd46baab597547Felipe Leme            if (count == null) {
46408703c8bb19b518214bc352199bd46baab597547Felipe Leme                uriCounters.put(app, new MutableInt(1));
46508703c8bb19b518214bc352199bd46baab597547Felipe Leme            } else {
46608703c8bb19b518214bc352199bd46baab597547Felipe Leme                count.value++;
46708703c8bb19b518214bc352199bd46baab597547Felipe Leme            }
46808703c8bb19b518214bc352199bd46baab597547Felipe Leme        }
46908703c8bb19b518214bc352199bd46baab597547Felipe Leme
47008703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Dynamically add the preferences, one per app.
47108703c8bb19b518214bc352199bd46baab597547Felipe Leme        int order = 0;
47208703c8bb19b518214bc352199bd46baab597547Felipe Leme        for (Map.Entry<CharSequence, MutableInt> entry : uriCounters.entrySet()) {
47308703c8bb19b518214bc352199bd46baab597547Felipe Leme            int numberResources = entry.getValue().value;
47408703c8bb19b518214bc352199bd46baab597547Felipe Leme            Preference pref = new Preference(getPrefContext());
47508703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setTitle(entry.getKey());
47608703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setSummary(getPrefContext().getResources()
47708703c8bb19b518214bc352199bd46baab597547Felipe Leme                    .getQuantityString(R.plurals.uri_permissions_text, numberResources,
47808703c8bb19b518214bc352199bd46baab597547Felipe Leme                            numberResources));
47908703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setSelectable(false);
48008703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setLayoutResource(R.layout.horizontal_preference);
48108703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setOrder(order);
48208703c8bb19b518214bc352199bd46baab597547Felipe Leme            Log.v(TAG, "Adding preference '" + pref + "' at order " + order);
48308703c8bb19b518214bc352199bd46baab597547Felipe Leme            mUri.addPreference(pref);
48408703c8bb19b518214bc352199bd46baab597547Felipe Leme        }
48508703c8bb19b518214bc352199bd46baab597547Felipe Leme
48608703c8bb19b518214bc352199bd46baab597547Felipe Leme        if (mAppControlRestricted) {
48708703c8bb19b518214bc352199bd46baab597547Felipe Leme            mClearUriButton.setEnabled(false);
48808703c8bb19b518214bc352199bd46baab597547Felipe Leme        }
48908703c8bb19b518214bc352199bd46baab597547Felipe Leme
49008703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUri.setOrder(order);
49108703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUriButton.setVisibility(View.VISIBLE);
49208703c8bb19b518214bc352199bd46baab597547Felipe Leme
49308703c8bb19b518214bc352199bd46baab597547Felipe Leme    }
49408703c8bb19b518214bc352199bd46baab597547Felipe Leme
49508703c8bb19b518214bc352199bd46baab597547Felipe Leme    private void clearUriPermissions() {
49608703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Synchronously revoke the permissions.
49708703c8bb19b518214bc352199bd46baab597547Felipe Leme        final ActivityManager am = (ActivityManager) getActivity().getSystemService(
49808703c8bb19b518214bc352199bd46baab597547Felipe Leme                Context.ACTIVITY_SERVICE);
49908703c8bb19b518214bc352199bd46baab597547Felipe Leme        am.clearGrantedUriPermissions(mAppEntry.info.packageName);
50008703c8bb19b518214bc352199bd46baab597547Felipe Leme
50108703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Update UI
50208703c8bb19b518214bc352199bd46baab597547Felipe Leme        refreshGrantedUriPermissions();
50308703c8bb19b518214bc352199bd46baab597547Felipe Leme    }
50408703c8bb19b518214bc352199bd46baab597547Felipe Leme
50508703c8bb19b518214bc352199bd46baab597547Felipe Leme    private void removeUriPermissionsFromUi() {
50608703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Remove all preferences but the clear button.
50708703c8bb19b518214bc352199bd46baab597547Felipe Leme        int count = mUri.getPreferenceCount();
50808703c8bb19b518214bc352199bd46baab597547Felipe Leme        for (int i = count - 1; i >= 0; i--) {
50908703c8bb19b518214bc352199bd46baab597547Felipe Leme            Preference pref = mUri.getPreference(i);
51008703c8bb19b518214bc352199bd46baab597547Felipe Leme            if (pref != mClearUri) {
51108703c8bb19b518214bc352199bd46baab597547Felipe Leme                mUri.removePreference(pref);
51208703c8bb19b518214bc352199bd46baab597547Felipe Leme            }
51308703c8bb19b518214bc352199bd46baab597547Felipe Leme        }
51408703c8bb19b518214bc352199bd46baab597547Felipe Leme    }
51508703c8bb19b518214bc352199bd46baab597547Felipe Leme
516cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
517cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    protected AlertDialog createDialog(int id, int errorCode) {
518cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        switch (id) {
519cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            case DLG_CLEAR_DATA:
520cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                return new AlertDialog.Builder(getActivity())
521cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setTitle(getActivity().getText(R.string.clear_data_dlg_title))
522cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setMessage(getActivity().getText(R.string.clear_data_dlg_text))
523cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
524cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            public void onClick(DialogInterface dialog, int which) {
525cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                // Clear user data here
526cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                initiateClearUserData();
527cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            }
528cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        })
529cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setNegativeButton(R.string.dlg_cancel, null)
530cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .create();
531cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            case DLG_CANNOT_CLEAR_DATA:
532cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                return new AlertDialog.Builder(getActivity())
533cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setTitle(getActivity().getText(R.string.clear_failed_dlg_title))
534cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setMessage(getActivity().getText(R.string.clear_failed_dlg_text))
535cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setNeutralButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
536cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            public void onClick(DialogInterface dialog, int which) {
537cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                mClearDataButton.setEnabled(false);
538cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                //force to recompute changed value
539cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                setIntentAndFinish(false, false);
540cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            }
541cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        })
542cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .create();
543cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
544cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        return null;
545cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
546cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
547cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
548cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    public void onPackageSizeChanged(String packageName) {
549cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (packageName.equals(mAppEntry.info.packageName)) {
550cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            refreshSizeInfo();
551cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
552cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
553cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
554cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private final Handler mHandler = new Handler() {
555cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        public void handleMessage(Message msg) {
556cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            if (getView() == null) {
557cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                return;
558cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
559cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            switch (msg.what) {
560cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                case MSG_CLEAR_USER_DATA:
561cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    processClearMsg(msg);
562cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    break;
563cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                case MSG_CLEAR_CACHE:
564cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    // Refresh size info
56507025891683aef83d850b0a91b37aa75b11ce33cJason Monk                    mState.requestSize(mPackageName, mUserId);
566cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    break;
567cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
568cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
569cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    };
570cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
571cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    public static CharSequence getSummary(AppEntry appEntry, Context context) {
572cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (appEntry.size == ApplicationsState.SIZE_INVALID
573cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                || appEntry.size == ApplicationsState.SIZE_UNKNOWN) {
574cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            return context.getText(R.string.computing_size);
575cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        } else {
576cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            CharSequence storageType = context.getString(
577cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    (appEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0
578cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    ? R.string.storage_type_external
579cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    : R.string.storage_type_internal);
580cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            return context.getString(R.string.storage_summary_format,
581cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    getSize(appEntry, context), storageType);
582cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
583cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
584cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
585cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static CharSequence getSize(AppEntry appEntry, Context context) {
586cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        long size = appEntry.size;
587cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (size == SIZE_INVALID) {
588cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            return context.getText(R.string.invalid_size_value);
589cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
590cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        return Formatter.formatFileSize(context, size);
591cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
592cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
5938a963babe2e36b7a41f77b8d2598c97658196e58Chris Wren    @Override
5948a963babe2e36b7a41f77b8d2598c97658196e58Chris Wren    protected int getMetricsCategory() {
5958a963babe2e36b7a41f77b8d2598c97658196e58Chris Wren        return MetricsLogger.APPLICATIONS_APP_STORAGE;
5968a963babe2e36b7a41f77b8d2598c97658196e58Chris Wren    }
5978a963babe2e36b7a41f77b8d2598c97658196e58Chris Wren
598cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    class ClearCacheObserver extends IPackageDataObserver.Stub {
599cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        public void onRemoveCompleted(final String packageName, final boolean succeeded) {
600cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            final Message msg = mHandler.obtainMessage(MSG_CLEAR_CACHE);
601cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            msg.arg1 = succeeded ? OP_SUCCESSFUL : OP_FAILED;
602cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mHandler.sendMessage(msg);
603cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
604cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
605cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
606cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    class ClearUserDataObserver extends IPackageDataObserver.Stub {
607cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk       public void onRemoveCompleted(final String packageName, final boolean succeeded) {
608cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk           final Message msg = mHandler.obtainMessage(MSG_CLEAR_USER_DATA);
60960a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk           msg.arg1 = succeeded ? OP_SUCCESSFUL : OP_FAILED;
610cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk           mHandler.sendMessage(msg);
611cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
612cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
613cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk}
614