AppStorageSettings.java revision 6a256e77d624967470f60c68dab6d5447e8a24cb
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;
223344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishiimport android.app.LoaderManager;
23cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.Context;
24cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.DialogInterface;
25cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.Intent;
263344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishiimport android.content.Loader;
2708703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport android.content.UriPermission;
28cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.pm.ApplicationInfo;
29cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.pm.IPackageDataObserver;
3008703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport android.content.pm.PackageManager;
3108703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport android.content.pm.ProviderInfo;
32cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.os.Bundle;
33cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.os.Environment;
34cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.os.Handler;
35cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.os.Message;
3616634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkeyimport android.os.RemoteException;
379e9f7d11162df92bc430002423a281e22176de41Jeff Sharkeyimport android.os.UserHandle;
381f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport android.os.storage.StorageManager;
391f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport android.os.storage.VolumeInfo;
4039b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.support.v7.preference.Preference;
4139b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.support.v7.preference.PreferenceCategory;
42cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.text.format.Formatter;
43cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.util.Log;
4408703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport android.util.MutableInt;
45cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.view.View;
46cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.view.View.OnClickListener;
47cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.widget.Button;
48cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
49265d3c2a0c36251bf8a9f571d7239b6dd404d942Tamas Berghammerimport com.android.internal.logging.nano.MetricsProto.MetricsEvent;
50cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport com.android.settings.R;
51cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport com.android.settings.Utils;
521f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport com.android.settings.deviceinfo.StorageWizardMoveConfirm;
53ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shankaimport com.android.settingslib.RestrictedLockUtils;
5467cd6ab93a526fe65877743e458590f4e6f187eeTony Mantlerimport com.android.settingslib.applications.ApplicationsState;
5567cd6ab93a526fe65877743e458590f4e6f187eeTony Mantlerimport com.android.settingslib.applications.ApplicationsState.AppEntry;
5667cd6ab93a526fe65877743e458590f4e6f187eeTony Mantlerimport com.android.settingslib.applications.ApplicationsState.Callbacks;
573344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishiimport com.android.settingslib.applications.StorageStatsSource;
583344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishiimport com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
591f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
601f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport java.util.Collections;
611f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport java.util.List;
6208703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport java.util.Map;
631f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport java.util.Objects;
6408703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport java.util.TreeMap;
65cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
668f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritzeimport static android.content.pm.ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
678f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritzeimport static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
688f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze
6960a09ea2388db01a661beeb9995a7ecf770a4200Jason Monkpublic class AppStorageSettings extends AppInfoWithHeader
703344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        implements OnClickListener, Callbacks, DialogInterface.OnClickListener,
713344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        LoaderManager.LoaderCallbacks<AppStorageStats> {
72588a0881c13d8ed63ba67b3145254c22211a2019Jason Monk    private static final String TAG = AppStorageSettings.class.getSimpleName();
73cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
74cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    //internal constants used in Handler
75cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int OP_SUCCESSFUL = 1;
76cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int OP_FAILED = 2;
77cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int MSG_CLEAR_USER_DATA = 1;
78cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int MSG_CLEAR_CACHE = 3;
79cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
80cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    // invalid size value used initially and also when size retrieval through PackageManager
81cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    // fails for whatever reason
82cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int SIZE_INVALID = -1;
83cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
84cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    // Result code identifiers
85cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    public static final int REQUEST_MANAGE_SPACE = 2;
86cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
87cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int DLG_CLEAR_DATA = DLG_BASE + 1;
88cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 2;
89cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
90e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private static final String KEY_STORAGE_USED = "storage_used";
91e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private static final String KEY_CHANGE_STORAGE = "change_storage_button";
92bd45c3cbe0ccb9d5a1ebeabccda1e803d613e729Jason Monk    private static final String KEY_STORAGE_SPACE = "storage_space";
93c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_STORAGE_CATEGORY = "storage_category";
9460a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk
95c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_TOTAL_SIZE = "total_size";
96c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_APP_SIZE = "app_size";
97c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_EXTERNAL_CODE_SIZE = "external_code_size";
98c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_DATA_SIZE = "data_size";
99c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_EXTERNAL_DATA_SIZE = "external_data_size";
100c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_CACHE_SIZE = "cache_size";
101c27f9e179adef2061e0000385f350874a7772c4eJason Monk
102c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_CLEAR_DATA = "clear_data_button";
103c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_CLEAR_CACHE = "clear_cache_button";
104c27f9e179adef2061e0000385f350874a7772c4eJason Monk
10508703c8bb19b518214bc352199bd46baab597547Felipe Leme    private static final String KEY_URI_CATEGORY = "uri_category";
10608703c8bb19b518214bc352199bd46baab597547Felipe Leme    private static final String KEY_CLEAR_URI = "clear_uri_button";
10708703c8bb19b518214bc352199bd46baab597547Felipe Leme
108cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    // Views related to cache info
109c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private Preference mCacheSize;
110cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private Button mClearDataButton;
111cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private Button mClearCacheButton;
11260a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk
113e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private Preference mStorageUsed;
114e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private Button mChangeStorageButton;
115cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
11608703c8bb19b518214bc352199bd46baab597547Felipe Leme    // Views related to URI permissions
11708703c8bb19b518214bc352199bd46baab597547Felipe Leme    private Button mClearUriButton;
11808703c8bb19b518214bc352199bd46baab597547Felipe Leme    private LayoutPreference mClearUri;
11908703c8bb19b518214bc352199bd46baab597547Felipe Leme    private PreferenceCategory mUri;
12008703c8bb19b518214bc352199bd46baab597547Felipe Leme
121cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private boolean mCanClearData = true;
122cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
1233344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    private AppStorageStats mLastResult;
1246a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi    private AppStorageSizesController mSizeController;
125cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
126cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private ClearCacheObserver mClearCacheObserver;
127cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private ClearUserDataObserver mClearDataObserver;
128cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
129cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    // Resource strings
130cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private CharSequence mInvalidSizeStr;
131cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private CharSequence mComputingStr;
132cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
133e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private VolumeInfo[] mCandidates;
134e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private AlertDialog.Builder mDialogBuilder;
1353344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    private ApplicationInfo mInfo;
136e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk
137cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
138cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    public void onCreate(Bundle savedInstanceState) {
139cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        super.onCreate(savedInstanceState);
140cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
14160a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk        addPreferencesFromResource(R.xml.app_storage_settings);
14260a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk        setupViews();
143b7a7158b18147afbeacca604788e28d0d1209b07Jason Monk        initMoveDialog();
144cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
145cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
146ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk    @Override
147ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk    public void onResume() {
148ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk        super.onResume();
1493344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        updateSize();
150ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk    }
151ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk
15260a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk    private void setupViews() {
153cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        mComputingStr = getActivity().getText(R.string.computing_size);
154cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        mInvalidSizeStr = getActivity().getText(R.string.invalid_size_value);
155cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
156cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        // Set default values on sizes
1576a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi        mSizeController = new AppStorageSizesController.Builder()
1586a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .setTotalSizePreference(findPreference(KEY_TOTAL_SIZE))
1596a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .setAppSizePreference(findPreference(KEY_APP_SIZE))
1606a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .setDataSizePreference(findPreference(KEY_DATA_SIZE))
1616a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .setCacheSizePreference(findPreference(KEY_CACHE_SIZE))
1626a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .setComputingString(R.string.computing_size)
1636a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .setErrorString(R.string.invalid_size_value)
1646a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .build();
1656a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi
166c27f9e179adef2061e0000385f350874a7772c4eJason Monk        mClearDataButton = (Button) ((LayoutPreference) findPreference(KEY_CLEAR_DATA))
16760a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk                .findViewById(R.id.button);
168cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
169e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mStorageUsed = findPreference(KEY_STORAGE_USED);
170e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mChangeStorageButton = (Button) ((LayoutPreference) findPreference(KEY_CHANGE_STORAGE))
171e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                .findViewById(R.id.button);
172e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mChangeStorageButton.setText(R.string.change);
173e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mChangeStorageButton.setOnClickListener(this);
174cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
175cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        // Cache section
176c27f9e179adef2061e0000385f350874a7772c4eJason Monk        mCacheSize = findPreference(KEY_CACHE_SIZE);
177c27f9e179adef2061e0000385f350874a7772c4eJason Monk        mClearCacheButton = (Button) ((LayoutPreference) findPreference(KEY_CLEAR_CACHE))
17860a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk                .findViewById(R.id.button);
17960a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk        mClearCacheButton.setText(R.string.clear_cache_btn_text);
18008703c8bb19b518214bc352199bd46baab597547Felipe Leme
18108703c8bb19b518214bc352199bd46baab597547Felipe Leme        // URI permissions section
18208703c8bb19b518214bc352199bd46baab597547Felipe Leme        mUri = (PreferenceCategory) findPreference(KEY_URI_CATEGORY);
18308703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUri = (LayoutPreference) mUri.findPreference(KEY_CLEAR_URI);
18408703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUriButton = (Button) mClearUri.findViewById(R.id.button);
18508703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUriButton.setText(R.string.clear_uri_btn_text);
18608703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUriButton.setOnClickListener(this);
187cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
188cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
189cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
190cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    public void onClick(View v) {
191cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (v == mClearCacheButton) {
1929e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka            if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) {
193ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
194ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                        getActivity(), mAppsControlDisallowedAdmin);
195ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                return;
196ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka            } else if (mClearCacheObserver == null) { // Lazy initialization of observer
197cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mClearCacheObserver = new ClearCacheObserver();
198cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
199cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mPm.deleteApplicationCacheFiles(mPackageName, mClearCacheObserver);
200e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        } else if (v == mClearDataButton) {
2019e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka            if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) {
202ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
203ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                        getActivity(), mAppsControlDisallowedAdmin);
204ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka            } else if (mAppEntry.info.manageSpaceActivityName != null) {
205cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                if (!Utils.isMonkeyRunning()) {
206cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    Intent intent = new Intent(Intent.ACTION_DEFAULT);
207cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    intent.setClassName(mAppEntry.info.packageName,
208cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            mAppEntry.info.manageSpaceActivityName);
209cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    startActivityForResult(intent, REQUEST_MANAGE_SPACE);
210cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                }
211cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            } else {
212cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                showDialogInner(DLG_CLEAR_DATA, 0);
213cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
21416634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey        } else if (v == mChangeStorageButton && mDialogBuilder != null && !isMoveInProgress()) {
215e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            mDialogBuilder.show();
21608703c8bb19b518214bc352199bd46baab597547Felipe Leme        } else if (v == mClearUriButton) {
2179e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka            if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) {
218ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
219ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                        getActivity(), mAppsControlDisallowedAdmin);
220ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka            } else {
221ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                clearUriPermissions();
222ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka            }
22360a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk        }
22460a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk    }
22560a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk
22616634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey    private boolean isMoveInProgress() {
22716634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey        try {
22816634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey            // TODO: define a cleaner API for this
2299e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey            AppGlobals.getPackageManager().checkPackageStartable(mPackageName,
2309e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey                    UserHandle.myUserId());
23116634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey            return false;
2329e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey        } catch (RemoteException | SecurityException e) {
2339e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey            return true;
23416634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey        }
23516634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey    }
23616634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey
23760a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk    @Override
238e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    public void onClick(DialogInterface dialog, int which) {
2391f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final Context context = getActivity();
2401f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
2411f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        // If not current volume, kick off move wizard
242e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        final VolumeInfo targetVol = mCandidates[which];
243954d8dad5e395544f95ca211466bcc7195d31877Jeff Sharkey        final VolumeInfo currentVol = context.getPackageManager().getPackageCurrentVolume(
2441f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey                mAppEntry.info);
2451f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        if (!Objects.equals(targetVol, currentVol)) {
2461f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey            final Intent intent = new Intent(context, StorageWizardMoveConfirm.class);
2471f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey            intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, targetVol.getId());
2481f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey            intent.putExtra(Intent.EXTRA_PACKAGE_NAME, mAppEntry.info.packageName);
2491f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey            startActivity(intent);
250cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
251e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        dialog.dismiss();
252cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
253cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
254cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
255cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    protected boolean refreshUi() {
256cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        retrieveAppEntry();
2579a1c0dce7a496f51087cf0497b931a31c64b0a65Julia Reynolds        if (mAppEntry == null) {
2589a1c0dce7a496f51087cf0497b931a31c64b0a65Julia Reynolds            return false;
2599a1c0dce7a496f51087cf0497b931a31c64b0a65Julia Reynolds        }
2603344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        updateUiWithSize(mLastResult);
26108703c8bb19b518214bc352199bd46baab597547Felipe Leme        refreshGrantedUriPermissions();
2621f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
2631f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final VolumeInfo currentVol = getActivity().getPackageManager()
264954d8dad5e395544f95ca211466bcc7195d31877Jeff Sharkey                .getPackageCurrentVolume(mAppEntry.info);
265e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        final StorageManager storage = getContext().getSystemService(StorageManager.class);
266e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mStorageUsed.setSummary(storage.getBestVolumeDescription(currentVol));
267e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk
268e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        refreshButtons();
2691f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
270cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        return true;
271cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
272cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
273cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private void refreshButtons() {
274e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        initMoveDialog();
2751f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        initDataButtons();
276cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
277cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
278cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private void initDataButtons() {
2798f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        final boolean appHasSpaceManagementUI = mAppEntry.info.manageSpaceActivityName != null;
2808f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        final boolean appHasActiveAdmins = mDpm.packageHasActiveAdmins(mPackageName);
2818f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        // Check that SYSTEM_APP flag is set, and ALLOW_CLEAR_USER_DATA is not set.
2828f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        final boolean isNonClearableSystemApp =
2838f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze                (mAppEntry.info.flags & (FLAG_SYSTEM | FLAG_ALLOW_CLEAR_USER_DATA)) == FLAG_SYSTEM;
2848f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        final boolean appRestrictsClearingData = isNonClearableSystemApp || appHasActiveAdmins;
2858f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze
2868f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        final Intent intent = new Intent(Intent.ACTION_DEFAULT);
2878f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        if (appHasSpaceManagementUI) {
2888f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze            intent.setClassName(mAppEntry.info.packageName, mAppEntry.info.manageSpaceActivityName);
2898f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        }
2908f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        final boolean isManageSpaceActivityAvailable =
2918f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze                getPackageManager().resolveActivity(intent, 0) != null;
2928f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze
2938f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        if ((!appHasSpaceManagementUI && appRestrictsClearingData)
2948f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze                || !isManageSpaceActivityAvailable) {
295cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataButton.setText(R.string.clear_user_data_text);
296cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataButton.setEnabled(false);
297cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mCanClearData = false;
298cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        } else {
2998f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze            if (appHasSpaceManagementUI) {
300cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mClearDataButton.setText(R.string.manage_space_text);
301cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            } else {
302cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mClearDataButton.setText(R.string.clear_user_data_text);
303cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
304cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataButton.setOnClickListener(this);
305cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
3069e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka
3079e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka        if (mAppsControlDisallowedBySystem) {
3089e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka            mClearDataButton.setEnabled(false);
3099e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka        }
310cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
311cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
312e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private void initMoveDialog() {
3131f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final Context context = getActivity();
3141f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final StorageManager storage = context.getSystemService(StorageManager.class);
3151f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
3161f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final List<VolumeInfo> candidates = context.getPackageManager()
317954d8dad5e395544f95ca211466bcc7195d31877Jeff Sharkey                .getPackageCandidateVolumes(mAppEntry.info);
318c27f9e179adef2061e0000385f350874a7772c4eJason Monk        if (candidates.size() > 1) {
319c27f9e179adef2061e0000385f350874a7772c4eJason Monk            Collections.sort(candidates, VolumeInfo.getDescriptionComparator());
3201f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
321e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            CharSequence[] labels = new CharSequence[candidates.size()];
322e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            int current = -1;
323e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            for (int i = 0; i < candidates.size(); i++) {
324e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                final String volDescrip = storage.getBestVolumeDescription(candidates.get(i));
325e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                if (Objects.equals(volDescrip, mStorageUsed.getSummary())) {
326e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                    current = i;
327e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                }
328e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                labels[i] = volDescrip;
329c27f9e179adef2061e0000385f350874a7772c4eJason Monk            }
330e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            mCandidates = candidates.toArray(new VolumeInfo[candidates.size()]);
331e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            mDialogBuilder = new AlertDialog.Builder(getContext())
332e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                    .setTitle(R.string.change_storage)
333e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                    .setSingleChoiceItems(labels, current, this)
334e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                    .setNegativeButton(R.string.cancel, null);
335c27f9e179adef2061e0000385f350874a7772c4eJason Monk        } else {
336e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            removePreference(KEY_STORAGE_USED);
337e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            removePreference(KEY_CHANGE_STORAGE);
338bd45c3cbe0ccb9d5a1ebeabccda1e803d613e729Jason Monk            removePreference(KEY_STORAGE_SPACE);
339cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
340cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
341cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
342cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    /*
343cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     * Private method to initiate clearing user data when the user clicks the clear data
344cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     * button for a system package
345cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     */
346cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private void initiateClearUserData() {
347cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        mClearDataButton.setEnabled(false);
348cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        // Invoke uninstall or clear user data based on sysPackage
349cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        String packageName = mAppEntry.info.packageName;
350cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        Log.i(TAG, "Clearing user data for package : " + packageName);
351cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (mClearDataObserver == null) {
352cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataObserver = new ClearUserDataObserver();
353cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
354cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        ActivityManager am = (ActivityManager)
355cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                getActivity().getSystemService(Context.ACTIVITY_SERVICE);
356cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        boolean res = am.clearApplicationUserData(packageName, mClearDataObserver);
357cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (!res) {
358cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            // Clearing data failed for some obscure reason. Just log error for now
359cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            Log.i(TAG, "Couldnt clear application user data for package:"+packageName);
360cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            showDialogInner(DLG_CANNOT_CLEAR_DATA, 0);
361cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        } else {
362cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataButton.setText(R.string.recompute_size);
363cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
364cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
365cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
366cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    /*
367cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     * Private method to handle clear message notification from observer when
368cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     * the async operation from PackageManager is complete
369cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     */
370cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private void processClearMsg(Message msg) {
371cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        int result = msg.arg1;
372cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        String packageName = mAppEntry.info.packageName;
373cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        mClearDataButton.setText(R.string.clear_user_data_text);
37460a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk        if (result == OP_SUCCESSFUL) {
375cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            Log.i(TAG, "Cleared user data for package : "+packageName);
3763344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            updateSize();
377cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        } else {
378cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataButton.setEnabled(true);
379cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
380cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
381cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
38208703c8bb19b518214bc352199bd46baab597547Felipe Leme    private void refreshGrantedUriPermissions() {
38308703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Clear UI first (in case the activity has been resumed)
38408703c8bb19b518214bc352199bd46baab597547Felipe Leme        removeUriPermissionsFromUi();
38508703c8bb19b518214bc352199bd46baab597547Felipe Leme
38608703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Gets all URI permissions from am.
38708703c8bb19b518214bc352199bd46baab597547Felipe Leme        ActivityManager am = (ActivityManager) getActivity().getSystemService(
38808703c8bb19b518214bc352199bd46baab597547Felipe Leme                Context.ACTIVITY_SERVICE);
38908703c8bb19b518214bc352199bd46baab597547Felipe Leme        List<UriPermission> perms =
39008703c8bb19b518214bc352199bd46baab597547Felipe Leme                am.getGrantedUriPermissions(mAppEntry.info.packageName).getList();
39108703c8bb19b518214bc352199bd46baab597547Felipe Leme
39208703c8bb19b518214bc352199bd46baab597547Felipe Leme        if (perms.isEmpty()) {
39308703c8bb19b518214bc352199bd46baab597547Felipe Leme            mClearUriButton.setVisibility(View.GONE);
39408703c8bb19b518214bc352199bd46baab597547Felipe Leme            return;
39508703c8bb19b518214bc352199bd46baab597547Felipe Leme        }
39608703c8bb19b518214bc352199bd46baab597547Felipe Leme
39708703c8bb19b518214bc352199bd46baab597547Felipe Leme        PackageManager pm = getActivity().getPackageManager();
39808703c8bb19b518214bc352199bd46baab597547Felipe Leme
39908703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Group number of URIs by app.
40008703c8bb19b518214bc352199bd46baab597547Felipe Leme        Map<CharSequence, MutableInt> uriCounters = new TreeMap<>();
40108703c8bb19b518214bc352199bd46baab597547Felipe Leme        for (UriPermission perm : perms) {
40208703c8bb19b518214bc352199bd46baab597547Felipe Leme            String authority = perm.getUri().getAuthority();
40308703c8bb19b518214bc352199bd46baab597547Felipe Leme            ProviderInfo provider = pm.resolveContentProvider(authority, 0);
40408703c8bb19b518214bc352199bd46baab597547Felipe Leme            CharSequence app = provider.applicationInfo.loadLabel(pm);
40508703c8bb19b518214bc352199bd46baab597547Felipe Leme            MutableInt count = uriCounters.get(app);
40608703c8bb19b518214bc352199bd46baab597547Felipe Leme            if (count == null) {
40708703c8bb19b518214bc352199bd46baab597547Felipe Leme                uriCounters.put(app, new MutableInt(1));
40808703c8bb19b518214bc352199bd46baab597547Felipe Leme            } else {
40908703c8bb19b518214bc352199bd46baab597547Felipe Leme                count.value++;
41008703c8bb19b518214bc352199bd46baab597547Felipe Leme            }
41108703c8bb19b518214bc352199bd46baab597547Felipe Leme        }
41208703c8bb19b518214bc352199bd46baab597547Felipe Leme
41308703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Dynamically add the preferences, one per app.
41408703c8bb19b518214bc352199bd46baab597547Felipe Leme        int order = 0;
41508703c8bb19b518214bc352199bd46baab597547Felipe Leme        for (Map.Entry<CharSequence, MutableInt> entry : uriCounters.entrySet()) {
41608703c8bb19b518214bc352199bd46baab597547Felipe Leme            int numberResources = entry.getValue().value;
41708703c8bb19b518214bc352199bd46baab597547Felipe Leme            Preference pref = new Preference(getPrefContext());
41808703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setTitle(entry.getKey());
41908703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setSummary(getPrefContext().getResources()
42008703c8bb19b518214bc352199bd46baab597547Felipe Leme                    .getQuantityString(R.plurals.uri_permissions_text, numberResources,
42108703c8bb19b518214bc352199bd46baab597547Felipe Leme                            numberResources));
42208703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setSelectable(false);
42308703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setLayoutResource(R.layout.horizontal_preference);
42408703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setOrder(order);
42508703c8bb19b518214bc352199bd46baab597547Felipe Leme            Log.v(TAG, "Adding preference '" + pref + "' at order " + order);
42608703c8bb19b518214bc352199bd46baab597547Felipe Leme            mUri.addPreference(pref);
42708703c8bb19b518214bc352199bd46baab597547Felipe Leme        }
42808703c8bb19b518214bc352199bd46baab597547Felipe Leme
4299e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka        if (mAppsControlDisallowedBySystem) {
4309e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka            mClearUriButton.setEnabled(false);
4319e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka        }
4329e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka
43308703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUri.setOrder(order);
43408703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUriButton.setVisibility(View.VISIBLE);
43508703c8bb19b518214bc352199bd46baab597547Felipe Leme
43608703c8bb19b518214bc352199bd46baab597547Felipe Leme    }
43708703c8bb19b518214bc352199bd46baab597547Felipe Leme
43808703c8bb19b518214bc352199bd46baab597547Felipe Leme    private void clearUriPermissions() {
43908703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Synchronously revoke the permissions.
44008703c8bb19b518214bc352199bd46baab597547Felipe Leme        final ActivityManager am = (ActivityManager) getActivity().getSystemService(
44108703c8bb19b518214bc352199bd46baab597547Felipe Leme                Context.ACTIVITY_SERVICE);
44208703c8bb19b518214bc352199bd46baab597547Felipe Leme        am.clearGrantedUriPermissions(mAppEntry.info.packageName);
44308703c8bb19b518214bc352199bd46baab597547Felipe Leme
44408703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Update UI
44508703c8bb19b518214bc352199bd46baab597547Felipe Leme        refreshGrantedUriPermissions();
44608703c8bb19b518214bc352199bd46baab597547Felipe Leme    }
44708703c8bb19b518214bc352199bd46baab597547Felipe Leme
44808703c8bb19b518214bc352199bd46baab597547Felipe Leme    private void removeUriPermissionsFromUi() {
44908703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Remove all preferences but the clear button.
45008703c8bb19b518214bc352199bd46baab597547Felipe Leme        int count = mUri.getPreferenceCount();
45108703c8bb19b518214bc352199bd46baab597547Felipe Leme        for (int i = count - 1; i >= 0; i--) {
45208703c8bb19b518214bc352199bd46baab597547Felipe Leme            Preference pref = mUri.getPreference(i);
45308703c8bb19b518214bc352199bd46baab597547Felipe Leme            if (pref != mClearUri) {
45408703c8bb19b518214bc352199bd46baab597547Felipe Leme                mUri.removePreference(pref);
45508703c8bb19b518214bc352199bd46baab597547Felipe Leme            }
45608703c8bb19b518214bc352199bd46baab597547Felipe Leme        }
45708703c8bb19b518214bc352199bd46baab597547Felipe Leme    }
45808703c8bb19b518214bc352199bd46baab597547Felipe Leme
459cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
460cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    protected AlertDialog createDialog(int id, int errorCode) {
461cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        switch (id) {
462cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            case DLG_CLEAR_DATA:
463cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                return new AlertDialog.Builder(getActivity())
464cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setTitle(getActivity().getText(R.string.clear_data_dlg_title))
465cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setMessage(getActivity().getText(R.string.clear_data_dlg_text))
466cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
467cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            public void onClick(DialogInterface dialog, int which) {
468cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                // Clear user data here
469cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                initiateClearUserData();
470cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            }
471cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        })
472cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setNegativeButton(R.string.dlg_cancel, null)
473cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .create();
474cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            case DLG_CANNOT_CLEAR_DATA:
475cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                return new AlertDialog.Builder(getActivity())
476cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setTitle(getActivity().getText(R.string.clear_failed_dlg_title))
477cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setMessage(getActivity().getText(R.string.clear_failed_dlg_text))
478cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setNeutralButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
479cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            public void onClick(DialogInterface dialog, int which) {
480cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                mClearDataButton.setEnabled(false);
481cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                //force to recompute changed value
482cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                setIntentAndFinish(false, false);
483cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            }
484cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        })
485cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .create();
486cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
487cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        return null;
488cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
489cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
490cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
491cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    public void onPackageSizeChanged(String packageName) {
4923344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    }
4933344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
4943344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    @Override
4953344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    public Loader<AppStorageStats> onCreateLoader(int id, Bundle args) {
4963344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        Context context = getContext();
4973344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        return new FetchPackageStorageAsyncLoader(
4983344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi                context, new StorageStatsSource(context), mInfo, UserHandle.of(mUserId));
4993344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    }
5003344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5013344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    @Override
5023344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    public void onLoadFinished(Loader<AppStorageStats> loader, AppStorageStats result) {
5036a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi        mSizeController.setResult(result);
5043344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        updateUiWithSize(result);
5053344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    }
5063344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5073344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    @Override
5083344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    public void onLoaderReset(Loader<AppStorageStats> loader) {
5093344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    }
5103344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5113344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    private void updateSize() {
5123344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        PackageManager packageManager = getPackageManager();
5133344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        try {
5143344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            mInfo = packageManager.getApplicationInfo(mPackageName, 0);
5153344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        } catch (PackageManager.NameNotFoundException e) {
5163344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            Log.e(TAG, "Could not find package", e);
5173344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        }
5183344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5193344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        if (mInfo == null) {
5203344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            return;
5213344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        }
5223344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5233344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        getLoaderManager().restartLoader(1, Bundle.EMPTY, this);
5243344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    }
5253344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5263344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    private void updateUiWithSize(AppStorageStats result) {
5276a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi        mSizeController.updateUi(getContext());
5286a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi
5293344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        if (result == null) {
5303344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            mClearDataButton.setEnabled(false);
5313344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            mClearCacheButton.setEnabled(false);
5323344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        } else {
5333344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            long codeSize = result.getCodeBytes();
5343344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            long dataSize = result.getDataBytes();
5353344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            long cacheSize = result.getCacheBytes();
5363344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5373344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            if (dataSize <= 0 || !mCanClearData) {
5383344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi                mClearDataButton.setEnabled(false);
5393344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            } else {
5403344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi                mClearDataButton.setEnabled(true);
5413344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi                mClearDataButton.setOnClickListener(this);
5423344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            }
5433344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            if (cacheSize <= 0) {
5443344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi                mClearCacheButton.setEnabled(false);
5453344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            } else {
5463344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi                mClearCacheButton.setEnabled(true);
5473344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi                mClearCacheButton.setOnClickListener(this);
5483344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            }
5493344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        }
5503344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        if (mAppsControlDisallowedBySystem) {
5513344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            mClearCacheButton.setEnabled(false);
5523344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            mClearDataButton.setEnabled(false);
553cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
554cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
555cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
556cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private final Handler mHandler = new Handler() {
557cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        public void handleMessage(Message msg) {
558cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            if (getView() == null) {
559cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                return;
560cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
561cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            switch (msg.what) {
562cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                case MSG_CLEAR_USER_DATA:
563cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    processClearMsg(msg);
564cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    break;
565cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                case MSG_CLEAR_CACHE:
566cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    // Refresh size info
5673344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi                    updateSize();
568cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    break;
569cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
570cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
571cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    };
572cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
5738a963babe2e36b7a41f77b8d2598c97658196e58Chris Wren    @Override
5746507613ebcd22e4691c2af92a5c161bd327db336Fan Zhang    public int getMetricsCategory() {
5759d1bfd1e8de6e46137a9571507c03526880d6a46Chris Wren        return MetricsEvent.APPLICATIONS_APP_STORAGE;
5768a963babe2e36b7a41f77b8d2598c97658196e58Chris Wren    }
5778a963babe2e36b7a41f77b8d2598c97658196e58Chris Wren
578cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    class ClearCacheObserver extends IPackageDataObserver.Stub {
579cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        public void onRemoveCompleted(final String packageName, final boolean succeeded) {
580cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            final Message msg = mHandler.obtainMessage(MSG_CLEAR_CACHE);
581cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            msg.arg1 = succeeded ? OP_SUCCESSFUL : OP_FAILED;
582cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mHandler.sendMessage(msg);
583cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
584cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
585cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
586cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    class ClearUserDataObserver extends IPackageDataObserver.Stub {
587cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk       public void onRemoveCompleted(final String packageName, final boolean succeeded) {
588cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk           final Message msg = mHandler.obtainMessage(MSG_CLEAR_USER_DATA);
58960a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk           msg.arg1 = succeeded ? OP_SUCCESSFUL : OP_FAILED;
590cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk           mHandler.sendMessage(msg);
591cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
592cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
593cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk}
594