AppStorageSettings.java revision ac06e1eeae81ace0563db11494420b7fb51cfe50
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
19ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhangimport static android.content.pm.ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
20ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhangimport static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
21ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang
22cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.app.ActivityManager;
23cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.app.AlertDialog;
2416634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkeyimport android.app.AppGlobals;
253344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishiimport android.app.LoaderManager;
26cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.Context;
27cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.DialogInterface;
28cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.Intent;
293344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishiimport android.content.Loader;
3008703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport android.content.UriPermission;
31cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.pm.ApplicationInfo;
32cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.pm.IPackageDataObserver;
3308703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport android.content.pm.PackageManager;
3408703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport android.content.pm.ProviderInfo;
35cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.os.Bundle;
36cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.os.Handler;
37cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.os.Message;
3816634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkeyimport android.os.RemoteException;
399e9f7d11162df92bc430002423a281e22176de41Jeff Sharkeyimport android.os.UserHandle;
401f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport android.os.storage.StorageManager;
411f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport android.os.storage.VolumeInfo;
42ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhangimport android.support.annotation.VisibleForTesting;
4339b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.support.v7.preference.Preference;
4439b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.support.v7.preference.PreferenceCategory;
45cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.util.Log;
4608703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport android.util.MutableInt;
47cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.view.View;
48cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.view.View.OnClickListener;
49cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.widget.Button;
50cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
51265d3c2a0c36251bf8a9f571d7239b6dd404d942Tamas Berghammerimport com.android.internal.logging.nano.MetricsProto.MetricsEvent;
52cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport com.android.settings.R;
53cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport com.android.settings.Utils;
541f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport com.android.settings.deviceinfo.StorageWizardMoveConfirm;
55ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhangimport com.android.settings.widget.ActionButtonPreference;
56ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shankaimport com.android.settingslib.RestrictedLockUtils;
5767cd6ab93a526fe65877743e458590f4e6f187eeTony Mantlerimport com.android.settingslib.applications.ApplicationsState.Callbacks;
583344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishiimport com.android.settingslib.applications.StorageStatsSource;
593344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishiimport com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
601f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
611f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport java.util.Collections;
621f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport java.util.List;
6308703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport java.util.Map;
641f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport java.util.Objects;
6508703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport java.util.TreeMap;
66cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
6760a09ea2388db01a661beeb9995a7ecf770a4200Jason Monkpublic class AppStorageSettings extends AppInfoWithHeader
683344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        implements OnClickListener, Callbacks, DialogInterface.OnClickListener,
693344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        LoaderManager.LoaderCallbacks<AppStorageStats> {
70588a0881c13d8ed63ba67b3145254c22211a2019Jason Monk    private static final String TAG = AppStorageSettings.class.getSimpleName();
71cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
72cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    //internal constants used in Handler
73cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int OP_SUCCESSFUL = 1;
74cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int OP_FAILED = 2;
75cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int MSG_CLEAR_USER_DATA = 1;
76cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int MSG_CLEAR_CACHE = 3;
77cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
78cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    // invalid size value used initially and also when size retrieval through PackageManager
79cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    // fails for whatever reason
80cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int SIZE_INVALID = -1;
81cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
82cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    // Result code identifiers
83cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    public static final int REQUEST_MANAGE_SPACE = 2;
84cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
85cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int DLG_CLEAR_DATA = DLG_BASE + 1;
86cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 2;
87cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
88e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private static final String KEY_STORAGE_USED = "storage_used";
89e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private static final String KEY_CHANGE_STORAGE = "change_storage_button";
90bd45c3cbe0ccb9d5a1ebeabccda1e803d613e729Jason Monk    private static final String KEY_STORAGE_SPACE = "storage_space";
91c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_STORAGE_CATEGORY = "storage_category";
9260a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk
93c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_TOTAL_SIZE = "total_size";
94c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_APP_SIZE = "app_size";
95c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_DATA_SIZE = "data_size";
96c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_CACHE_SIZE = "cache_size";
97c27f9e179adef2061e0000385f350874a7772c4eJason Monk
98e7202b5c3d4deebf236bcfd435d7a7eecc254ab5Daniel Nishi    private static final String KEY_HEADER_BUTTONS = "header_view";
99c27f9e179adef2061e0000385f350874a7772c4eJason Monk
10008703c8bb19b518214bc352199bd46baab597547Felipe Leme    private static final String KEY_URI_CATEGORY = "uri_category";
10108703c8bb19b518214bc352199bd46baab597547Felipe Leme    private static final String KEY_CLEAR_URI = "clear_uri_button";
10208703c8bb19b518214bc352199bd46baab597547Felipe Leme
1031359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi    private static final String KEY_CACHE_CLEARED = "cache_cleared";
104278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi    private static final String KEY_DATA_CLEARED = "data_cleared";
1051359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi
106cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    // Views related to cache info
107ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang    @VisibleForTesting
108ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang    ActionButtonPreference mButtonsPref;
10960a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk
110e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private Preference mStorageUsed;
111e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private Button mChangeStorageButton;
112cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
11308703c8bb19b518214bc352199bd46baab597547Felipe Leme    // Views related to URI permissions
11408703c8bb19b518214bc352199bd46baab597547Felipe Leme    private Button mClearUriButton;
11508703c8bb19b518214bc352199bd46baab597547Felipe Leme    private LayoutPreference mClearUri;
11608703c8bb19b518214bc352199bd46baab597547Felipe Leme    private PreferenceCategory mUri;
11708703c8bb19b518214bc352199bd46baab597547Felipe Leme
118cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private boolean mCanClearData = true;
1191359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi    private boolean mCacheCleared;
120278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi    private boolean mDataCleared;
121cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
122ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang    @VisibleForTesting
123ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang    AppStorageSizesController mSizeController;
124cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
125cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private ClearCacheObserver mClearCacheObserver;
126cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private ClearUserDataObserver mClearDataObserver;
127cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
128e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private VolumeInfo[] mCandidates;
129e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private AlertDialog.Builder mDialogBuilder;
1303344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    private ApplicationInfo mInfo;
131e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk
132cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
133cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    public void onCreate(Bundle savedInstanceState) {
134cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        super.onCreate(savedInstanceState);
1351359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi        if (savedInstanceState != null) {
1361359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi            mCacheCleared = savedInstanceState.getBoolean(KEY_CACHE_CLEARED, false);
137278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi            mDataCleared = savedInstanceState.getBoolean(KEY_DATA_CLEARED, false);
138278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi            mCacheCleared = mCacheCleared || mDataCleared;
1391359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi        }
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
1521359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi    @Override
1531359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi    public void onSaveInstanceState(Bundle outState) {
1541359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi        super.onSaveInstanceState(outState);
1551359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi        outState.putBoolean(KEY_CACHE_CLEARED, mCacheCleared);
156278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi        outState.putBoolean(KEY_DATA_CLEARED, mDataCleared);
1571359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi    }
1581359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi
15960a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk    private void setupViews() {
160cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        // Set default values on sizes
1616a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi        mSizeController = new AppStorageSizesController.Builder()
1626a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .setTotalSizePreference(findPreference(KEY_TOTAL_SIZE))
1636a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .setAppSizePreference(findPreference(KEY_APP_SIZE))
1646a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .setDataSizePreference(findPreference(KEY_DATA_SIZE))
1656a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .setCacheSizePreference(findPreference(KEY_CACHE_SIZE))
1666a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .setComputingString(R.string.computing_size)
1676a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .setErrorString(R.string.invalid_size_value)
1686a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .build();
169ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang        mButtonsPref = ((ActionButtonPreference) findPreference(KEY_HEADER_BUTTONS))
170ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                .setButton1Positive(false)
171ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                .setButton2Positive(false);
172cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
173e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mStorageUsed = findPreference(KEY_STORAGE_USED);
174e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mChangeStorageButton = (Button) ((LayoutPreference) findPreference(KEY_CHANGE_STORAGE))
175e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                .findViewById(R.id.button);
176e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mChangeStorageButton.setText(R.string.change);
177e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mChangeStorageButton.setOnClickListener(this);
178cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
179cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        // Cache section
180ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang        mButtonsPref.setButton2Text(R.string.clear_cache_btn_text);
18108703c8bb19b518214bc352199bd46baab597547Felipe Leme
18208703c8bb19b518214bc352199bd46baab597547Felipe Leme        // URI permissions section
18308703c8bb19b518214bc352199bd46baab597547Felipe Leme        mUri = (PreferenceCategory) findPreference(KEY_URI_CATEGORY);
18408703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUri = (LayoutPreference) mUri.findPreference(KEY_CLEAR_URI);
18508703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUriButton = (Button) mClearUri.findViewById(R.id.button);
18608703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUriButton.setText(R.string.clear_uri_btn_text);
18708703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUriButton.setOnClickListener(this);
188cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
189cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
190ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang    @VisibleForTesting
191ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang    void handleClearCacheClick() {
192ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang        if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) {
193ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
194ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                    getActivity(), mAppsControlDisallowedAdmin);
195ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            return;
196ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang        } else if (mClearCacheObserver == null) { // Lazy initialization of observer
197ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            mClearCacheObserver = new ClearCacheObserver();
198ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang        }
199ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang        mMetricsFeatureProvider.action(getContext(),
200ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                MetricsEvent.ACTION_SETTINGS_CLEAR_APP_CACHE);
201ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang        mPm.deleteApplicationCacheFiles(mPackageName, mClearCacheObserver);
202ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang    }
203ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang
204ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang    @VisibleForTesting
205ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang    void handleClearDataClick() {
206ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang        if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) {
207ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
208ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                    getActivity(), mAppsControlDisallowedAdmin);
209ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang        } else if (mAppEntry.info.manageSpaceActivityName != null) {
210ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            if (!Utils.isMonkeyRunning()) {
211ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                Intent intent = new Intent(Intent.ACTION_DEFAULT);
212ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                intent.setClassName(mAppEntry.info.packageName,
213ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                        mAppEntry.info.manageSpaceActivityName);
214ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                startActivityForResult(intent, REQUEST_MANAGE_SPACE);
215ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            }
216ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang        } else {
217ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            showDialogInner(DLG_CLEAR_DATA, 0);
218ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang        }
219ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang    }
220ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang
221cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
222cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    public void onClick(View v) {
223ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang        if (v == mChangeStorageButton && mDialogBuilder != null && !isMoveInProgress()) {
224e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            mDialogBuilder.show();
22508703c8bb19b518214bc352199bd46baab597547Felipe Leme        } else if (v == mClearUriButton) {
2269e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka            if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) {
227ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
228ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                        getActivity(), mAppsControlDisallowedAdmin);
229ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka            } else {
230ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                clearUriPermissions();
231ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka            }
23260a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk        }
23360a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk    }
23460a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk
23516634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey    private boolean isMoveInProgress() {
23616634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey        try {
23716634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey            // TODO: define a cleaner API for this
2389e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey            AppGlobals.getPackageManager().checkPackageStartable(mPackageName,
2399e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey                    UserHandle.myUserId());
24016634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey            return false;
2419e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey        } catch (RemoteException | SecurityException e) {
2429e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey            return true;
24316634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey        }
24416634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey    }
24516634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey
24660a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk    @Override
247e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    public void onClick(DialogInterface dialog, int which) {
2481f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final Context context = getActivity();
2491f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
2501f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        // If not current volume, kick off move wizard
251e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        final VolumeInfo targetVol = mCandidates[which];
252954d8dad5e395544f95ca211466bcc7195d31877Jeff Sharkey        final VolumeInfo currentVol = context.getPackageManager().getPackageCurrentVolume(
2531f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey                mAppEntry.info);
2541f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        if (!Objects.equals(targetVol, currentVol)) {
2551f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey            final Intent intent = new Intent(context, StorageWizardMoveConfirm.class);
2561f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey            intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, targetVol.getId());
2571f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey            intent.putExtra(Intent.EXTRA_PACKAGE_NAME, mAppEntry.info.packageName);
2581f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey            startActivity(intent);
259cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
260e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        dialog.dismiss();
261cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
262cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
263cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
264cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    protected boolean refreshUi() {
265cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        retrieveAppEntry();
2669a1c0dce7a496f51087cf0497b931a31c64b0a65Julia Reynolds        if (mAppEntry == null) {
2679a1c0dce7a496f51087cf0497b931a31c64b0a65Julia Reynolds            return false;
2689a1c0dce7a496f51087cf0497b931a31c64b0a65Julia Reynolds        }
269e7202b5c3d4deebf236bcfd435d7a7eecc254ab5Daniel Nishi        updateUiWithSize(mSizeController.getLastResult());
27008703c8bb19b518214bc352199bd46baab597547Felipe Leme        refreshGrantedUriPermissions();
2711f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
2721f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final VolumeInfo currentVol = getActivity().getPackageManager()
273954d8dad5e395544f95ca211466bcc7195d31877Jeff Sharkey                .getPackageCurrentVolume(mAppEntry.info);
274e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        final StorageManager storage = getContext().getSystemService(StorageManager.class);
275e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mStorageUsed.setSummary(storage.getBestVolumeDescription(currentVol));
276e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk
277e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        refreshButtons();
2781f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
279cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        return true;
280cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
281cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
282cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private void refreshButtons() {
283e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        initMoveDialog();
2841f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        initDataButtons();
285cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
286cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
287cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private void initDataButtons() {
2888f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        final boolean appHasSpaceManagementUI = mAppEntry.info.manageSpaceActivityName != null;
2898f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        final boolean appHasActiveAdmins = mDpm.packageHasActiveAdmins(mPackageName);
2908f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        // Check that SYSTEM_APP flag is set, and ALLOW_CLEAR_USER_DATA is not set.
2918f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        final boolean isNonClearableSystemApp =
2928f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze                (mAppEntry.info.flags & (FLAG_SYSTEM | FLAG_ALLOW_CLEAR_USER_DATA)) == FLAG_SYSTEM;
2938f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        final boolean appRestrictsClearingData = isNonClearableSystemApp || appHasActiveAdmins;
2948f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze
2958f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        final Intent intent = new Intent(Intent.ACTION_DEFAULT);
2968f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        if (appHasSpaceManagementUI) {
2978f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze            intent.setClassName(mAppEntry.info.packageName, mAppEntry.info.manageSpaceActivityName);
2988f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        }
2998f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        final boolean isManageSpaceActivityAvailable =
3008f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze                getPackageManager().resolveActivity(intent, 0) != null;
3018f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze
3028f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        if ((!appHasSpaceManagementUI && appRestrictsClearingData)
3038f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze                || !isManageSpaceActivityAvailable) {
304ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            mButtonsPref
305ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                    .setButton1Text(R.string.clear_user_data_text)
306ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                    .setButton1Enabled(false);
307cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mCanClearData = false;
308cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        } else {
3098f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze            if (appHasSpaceManagementUI) {
310ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                mButtonsPref.setButton1Text(R.string.manage_space_text);
311cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            } else {
312ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                mButtonsPref.setButton1Text(R.string.clear_user_data_text);
313cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
314ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            mButtonsPref
315ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                    .setButton1Text(R.string.clear_user_data_text)
316ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                    .setButton1OnClickListener(v -> handleClearDataClick());
317cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
3189e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka
3199e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka        if (mAppsControlDisallowedBySystem) {
320ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            mButtonsPref.setButton1Enabled(false);
3219e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka        }
322cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
323cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
324e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private void initMoveDialog() {
3251f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final Context context = getActivity();
3261f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final StorageManager storage = context.getSystemService(StorageManager.class);
3271f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
3281f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final List<VolumeInfo> candidates = context.getPackageManager()
329954d8dad5e395544f95ca211466bcc7195d31877Jeff Sharkey                .getPackageCandidateVolumes(mAppEntry.info);
330c27f9e179adef2061e0000385f350874a7772c4eJason Monk        if (candidates.size() > 1) {
331c27f9e179adef2061e0000385f350874a7772c4eJason Monk            Collections.sort(candidates, VolumeInfo.getDescriptionComparator());
3321f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
333e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            CharSequence[] labels = new CharSequence[candidates.size()];
334e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            int current = -1;
335e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            for (int i = 0; i < candidates.size(); i++) {
336e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                final String volDescrip = storage.getBestVolumeDescription(candidates.get(i));
337e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                if (Objects.equals(volDescrip, mStorageUsed.getSummary())) {
338e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                    current = i;
339e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                }
340e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                labels[i] = volDescrip;
341c27f9e179adef2061e0000385f350874a7772c4eJason Monk            }
342e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            mCandidates = candidates.toArray(new VolumeInfo[candidates.size()]);
343e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            mDialogBuilder = new AlertDialog.Builder(getContext())
344e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                    .setTitle(R.string.change_storage)
345e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                    .setSingleChoiceItems(labels, current, this)
346e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                    .setNegativeButton(R.string.cancel, null);
347c27f9e179adef2061e0000385f350874a7772c4eJason Monk        } else {
348e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            removePreference(KEY_STORAGE_USED);
349e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            removePreference(KEY_CHANGE_STORAGE);
350bd45c3cbe0ccb9d5a1ebeabccda1e803d613e729Jason Monk            removePreference(KEY_STORAGE_SPACE);
351cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
352cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
353cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
354cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    /*
355cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     * Private method to initiate clearing user data when the user clicks the clear data
356cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     * button for a system package
357cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     */
358cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private void initiateClearUserData() {
359c49ab99007d74edf7086e8254cb6812771313b52Fan Zhang        mMetricsFeatureProvider.action(getContext(), MetricsEvent.ACTION_SETTINGS_CLEAR_APP_DATA);
360ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang        mButtonsPref.setButton1Enabled(false);
361cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        // Invoke uninstall or clear user data based on sysPackage
362cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        String packageName = mAppEntry.info.packageName;
363cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        Log.i(TAG, "Clearing user data for package : " + packageName);
364cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (mClearDataObserver == null) {
365cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataObserver = new ClearUserDataObserver();
366cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
367cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        ActivityManager am = (ActivityManager)
368cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                getActivity().getSystemService(Context.ACTIVITY_SERVICE);
369cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        boolean res = am.clearApplicationUserData(packageName, mClearDataObserver);
370cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (!res) {
371cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            // Clearing data failed for some obscure reason. Just log error for now
372ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            Log.i(TAG, "Couldnt clear application user data for package:" + packageName);
373cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            showDialogInner(DLG_CANNOT_CLEAR_DATA, 0);
374cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        } else {
375ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            mButtonsPref.setButton1Text(R.string.recompute_size);
376cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
377cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
378cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
379cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    /*
380cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     * Private method to handle clear message notification from observer when
381cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     * the async operation from PackageManager is complete
382cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     */
383cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private void processClearMsg(Message msg) {
384cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        int result = msg.arg1;
385cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        String packageName = mAppEntry.info.packageName;
386ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang        mButtonsPref.setButton1Text(R.string.clear_user_data_text);
38760a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk        if (result == OP_SUCCESSFUL) {
388ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            Log.i(TAG, "Cleared user data for package : " + packageName);
3893344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            updateSize();
390cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        } else {
391ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            mButtonsPref.setButton1Enabled(true);
392cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
393cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
394cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
39508703c8bb19b518214bc352199bd46baab597547Felipe Leme    private void refreshGrantedUriPermissions() {
39608703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Clear UI first (in case the activity has been resumed)
39708703c8bb19b518214bc352199bd46baab597547Felipe Leme        removeUriPermissionsFromUi();
39808703c8bb19b518214bc352199bd46baab597547Felipe Leme
39908703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Gets all URI permissions from am.
40008703c8bb19b518214bc352199bd46baab597547Felipe Leme        ActivityManager am = (ActivityManager) getActivity().getSystemService(
40108703c8bb19b518214bc352199bd46baab597547Felipe Leme                Context.ACTIVITY_SERVICE);
40208703c8bb19b518214bc352199bd46baab597547Felipe Leme        List<UriPermission> perms =
40308703c8bb19b518214bc352199bd46baab597547Felipe Leme                am.getGrantedUriPermissions(mAppEntry.info.packageName).getList();
40408703c8bb19b518214bc352199bd46baab597547Felipe Leme
40508703c8bb19b518214bc352199bd46baab597547Felipe Leme        if (perms.isEmpty()) {
40608703c8bb19b518214bc352199bd46baab597547Felipe Leme            mClearUriButton.setVisibility(View.GONE);
40708703c8bb19b518214bc352199bd46baab597547Felipe Leme            return;
40808703c8bb19b518214bc352199bd46baab597547Felipe Leme        }
40908703c8bb19b518214bc352199bd46baab597547Felipe Leme
41008703c8bb19b518214bc352199bd46baab597547Felipe Leme        PackageManager pm = getActivity().getPackageManager();
41108703c8bb19b518214bc352199bd46baab597547Felipe Leme
41208703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Group number of URIs by app.
41308703c8bb19b518214bc352199bd46baab597547Felipe Leme        Map<CharSequence, MutableInt> uriCounters = new TreeMap<>();
41408703c8bb19b518214bc352199bd46baab597547Felipe Leme        for (UriPermission perm : perms) {
41508703c8bb19b518214bc352199bd46baab597547Felipe Leme            String authority = perm.getUri().getAuthority();
41608703c8bb19b518214bc352199bd46baab597547Felipe Leme            ProviderInfo provider = pm.resolveContentProvider(authority, 0);
41708703c8bb19b518214bc352199bd46baab597547Felipe Leme            CharSequence app = provider.applicationInfo.loadLabel(pm);
41808703c8bb19b518214bc352199bd46baab597547Felipe Leme            MutableInt count = uriCounters.get(app);
41908703c8bb19b518214bc352199bd46baab597547Felipe Leme            if (count == null) {
42008703c8bb19b518214bc352199bd46baab597547Felipe Leme                uriCounters.put(app, new MutableInt(1));
42108703c8bb19b518214bc352199bd46baab597547Felipe Leme            } else {
42208703c8bb19b518214bc352199bd46baab597547Felipe Leme                count.value++;
42308703c8bb19b518214bc352199bd46baab597547Felipe Leme            }
42408703c8bb19b518214bc352199bd46baab597547Felipe Leme        }
42508703c8bb19b518214bc352199bd46baab597547Felipe Leme
42608703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Dynamically add the preferences, one per app.
42708703c8bb19b518214bc352199bd46baab597547Felipe Leme        int order = 0;
42808703c8bb19b518214bc352199bd46baab597547Felipe Leme        for (Map.Entry<CharSequence, MutableInt> entry : uriCounters.entrySet()) {
42908703c8bb19b518214bc352199bd46baab597547Felipe Leme            int numberResources = entry.getValue().value;
43008703c8bb19b518214bc352199bd46baab597547Felipe Leme            Preference pref = new Preference(getPrefContext());
43108703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setTitle(entry.getKey());
43208703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setSummary(getPrefContext().getResources()
43308703c8bb19b518214bc352199bd46baab597547Felipe Leme                    .getQuantityString(R.plurals.uri_permissions_text, numberResources,
43408703c8bb19b518214bc352199bd46baab597547Felipe Leme                            numberResources));
43508703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setSelectable(false);
43608703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setLayoutResource(R.layout.horizontal_preference);
43708703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setOrder(order);
43808703c8bb19b518214bc352199bd46baab597547Felipe Leme            Log.v(TAG, "Adding preference '" + pref + "' at order " + order);
43908703c8bb19b518214bc352199bd46baab597547Felipe Leme            mUri.addPreference(pref);
44008703c8bb19b518214bc352199bd46baab597547Felipe Leme        }
44108703c8bb19b518214bc352199bd46baab597547Felipe Leme
4429e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka        if (mAppsControlDisallowedBySystem) {
4439e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka            mClearUriButton.setEnabled(false);
4449e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka        }
4459e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka
44608703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUri.setOrder(order);
44708703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUriButton.setVisibility(View.VISIBLE);
44808703c8bb19b518214bc352199bd46baab597547Felipe Leme
44908703c8bb19b518214bc352199bd46baab597547Felipe Leme    }
45008703c8bb19b518214bc352199bd46baab597547Felipe Leme
45108703c8bb19b518214bc352199bd46baab597547Felipe Leme    private void clearUriPermissions() {
45208703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Synchronously revoke the permissions.
45308703c8bb19b518214bc352199bd46baab597547Felipe Leme        final ActivityManager am = (ActivityManager) getActivity().getSystemService(
45408703c8bb19b518214bc352199bd46baab597547Felipe Leme                Context.ACTIVITY_SERVICE);
45508703c8bb19b518214bc352199bd46baab597547Felipe Leme        am.clearGrantedUriPermissions(mAppEntry.info.packageName);
45608703c8bb19b518214bc352199bd46baab597547Felipe Leme
45708703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Update UI
45808703c8bb19b518214bc352199bd46baab597547Felipe Leme        refreshGrantedUriPermissions();
45908703c8bb19b518214bc352199bd46baab597547Felipe Leme    }
46008703c8bb19b518214bc352199bd46baab597547Felipe Leme
46108703c8bb19b518214bc352199bd46baab597547Felipe Leme    private void removeUriPermissionsFromUi() {
46208703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Remove all preferences but the clear button.
46308703c8bb19b518214bc352199bd46baab597547Felipe Leme        int count = mUri.getPreferenceCount();
46408703c8bb19b518214bc352199bd46baab597547Felipe Leme        for (int i = count - 1; i >= 0; i--) {
46508703c8bb19b518214bc352199bd46baab597547Felipe Leme            Preference pref = mUri.getPreference(i);
46608703c8bb19b518214bc352199bd46baab597547Felipe Leme            if (pref != mClearUri) {
46708703c8bb19b518214bc352199bd46baab597547Felipe Leme                mUri.removePreference(pref);
46808703c8bb19b518214bc352199bd46baab597547Felipe Leme            }
46908703c8bb19b518214bc352199bd46baab597547Felipe Leme        }
47008703c8bb19b518214bc352199bd46baab597547Felipe Leme    }
47108703c8bb19b518214bc352199bd46baab597547Felipe Leme
472cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
473cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    protected AlertDialog createDialog(int id, int errorCode) {
474cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        switch (id) {
475cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            case DLG_CLEAR_DATA:
476cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                return new AlertDialog.Builder(getActivity())
477cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setTitle(getActivity().getText(R.string.clear_data_dlg_title))
478cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setMessage(getActivity().getText(R.string.clear_data_dlg_text))
479cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
480cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            public void onClick(DialogInterface dialog, int which) {
481cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                // Clear user data here
482cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                initiateClearUserData();
483cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            }
484cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        })
485cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setNegativeButton(R.string.dlg_cancel, null)
486cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .create();
487cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            case DLG_CANNOT_CLEAR_DATA:
488cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                return new AlertDialog.Builder(getActivity())
489cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setTitle(getActivity().getText(R.string.clear_failed_dlg_title))
490cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setMessage(getActivity().getText(R.string.clear_failed_dlg_text))
491cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setNeutralButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
492cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            public void onClick(DialogInterface dialog, int which) {
493ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                                mButtonsPref.setButton1Enabled(false);
494cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                //force to recompute changed value
495cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                setIntentAndFinish(false, false);
496cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            }
497cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        })
498cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .create();
499cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
500cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        return null;
501cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
502cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
503cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
504cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    public void onPackageSizeChanged(String packageName) {
5053344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    }
5063344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5073344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    @Override
5083344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    public Loader<AppStorageStats> onCreateLoader(int id, Bundle args) {
5093344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        Context context = getContext();
5103344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        return new FetchPackageStorageAsyncLoader(
5113344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi                context, new StorageStatsSource(context), mInfo, UserHandle.of(mUserId));
5123344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    }
5133344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5143344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    @Override
5153344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    public void onLoadFinished(Loader<AppStorageStats> loader, AppStorageStats result) {
5166a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi        mSizeController.setResult(result);
5173344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        updateUiWithSize(result);
5183344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    }
5193344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5203344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    @Override
5213344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    public void onLoaderReset(Loader<AppStorageStats> loader) {
5223344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    }
5233344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5243344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    private void updateSize() {
5253344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        PackageManager packageManager = getPackageManager();
5263344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        try {
5273344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            mInfo = packageManager.getApplicationInfo(mPackageName, 0);
5283344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        } catch (PackageManager.NameNotFoundException e) {
5293344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            Log.e(TAG, "Could not find package", e);
5303344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        }
5313344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5323344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        if (mInfo == null) {
5333344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            return;
5343344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        }
5353344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5363344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        getLoaderManager().restartLoader(1, Bundle.EMPTY, this);
5373344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    }
5383344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
539ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang    @VisibleForTesting
540ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang    void updateUiWithSize(AppStorageStats result) {
5411359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi        if (mCacheCleared) {
5421359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi            mSizeController.setCacheCleared(true);
5431359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi        }
544278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi        if (mDataCleared) {
545278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi            mSizeController.setDataCleared(true);
546278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi        }
5471359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi
5486a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi        mSizeController.updateUi(getContext());
5496a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi
5503344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        if (result == null) {
551ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            mButtonsPref.setButton1Enabled(false).setButton2Enabled(false);
5523344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        } else {
5533344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            long cacheSize = result.getCacheBytes();
5546f92b661a4c3d4a064d536fd466918b44fdacef1Daniel Nishi            long dataSize = result.getDataBytes() - cacheSize;
5553344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
556278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi            if (dataSize <= 0 || !mCanClearData || mDataCleared) {
557ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                mButtonsPref.setButton1Enabled(false);
5583344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            } else {
559ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                mButtonsPref.setButton1Enabled(true)
560ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                        .setButton1OnClickListener(v -> handleClearDataClick());
5613344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            }
5621359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi            if (cacheSize <= 0 || mCacheCleared) {
563ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                mButtonsPref.setButton2Enabled(false);
5643344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            } else {
565ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                mButtonsPref.setButton2Enabled(true)
566ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang                        .setButton2OnClickListener(v -> handleClearCacheClick());
5673344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            }
5683344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        }
5693344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        if (mAppsControlDisallowedBySystem) {
570ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            mButtonsPref.setButton1Enabled(false).setButton2Enabled(false);
571cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
572cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
573cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
574cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private final Handler mHandler = new Handler() {
575cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        public void handleMessage(Message msg) {
576cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            if (getView() == null) {
577cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                return;
578cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
579cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            switch (msg.what) {
580cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                case MSG_CLEAR_USER_DATA:
581278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi                    mDataCleared = true;
582278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi                    mCacheCleared = true;
583cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    processClearMsg(msg);
584cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    break;
585cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                case MSG_CLEAR_CACHE:
5861359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi                    mCacheCleared = true;
587cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    // Refresh size info
5883344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi                    updateSize();
589cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    break;
590cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
591cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
592cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    };
593cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
5948a963babe2e36b7a41f77b8d2598c97658196e58Chris Wren    @Override
5956507613ebcd22e4691c2af92a5c161bd327db336Fan Zhang    public int getMetricsCategory() {
5969d1bfd1e8de6e46137a9571507c03526880d6a46Chris Wren        return MetricsEvent.APPLICATIONS_APP_STORAGE;
5978a963babe2e36b7a41f77b8d2598c97658196e58Chris Wren    }
5988a963babe2e36b7a41f77b8d2598c97658196e58Chris Wren
599cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    class ClearCacheObserver extends IPackageDataObserver.Stub {
600cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        public void onRemoveCompleted(final String packageName, final boolean succeeded) {
601cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            final Message msg = mHandler.obtainMessage(MSG_CLEAR_CACHE);
602cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            msg.arg1 = succeeded ? OP_SUCCESSFUL : OP_FAILED;
603cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mHandler.sendMessage(msg);
604cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
605cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
606cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
607cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    class ClearUserDataObserver extends IPackageDataObserver.Stub {
608ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang        public void onRemoveCompleted(final String packageName, final boolean succeeded) {
609ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            final Message msg = mHandler.obtainMessage(MSG_CLEAR_USER_DATA);
610ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            msg.arg1 = succeeded ? OP_SUCCESSFUL : OP_FAILED;
611ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang            mHandler.sendMessage(msg);
612cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
613cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
614cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk}
615