AppStorageSettings.java revision 278bea730d52f65275f184a54a149d8258bba17f
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.Handler;
34cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.os.Message;
3516634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkeyimport android.os.RemoteException;
369e9f7d11162df92bc430002423a281e22176de41Jeff Sharkeyimport android.os.UserHandle;
371f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport android.os.storage.StorageManager;
381f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport android.os.storage.VolumeInfo;
3939b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.support.v7.preference.Preference;
4039b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.support.v7.preference.PreferenceCategory;
41cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.util.Log;
4208703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport android.util.MutableInt;
43cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.view.View;
44cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.view.View.OnClickListener;
45cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.widget.Button;
46cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
47265d3c2a0c36251bf8a9f571d7239b6dd404d942Tamas Berghammerimport com.android.internal.logging.nano.MetricsProto.MetricsEvent;
48cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport com.android.settings.R;
49cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport com.android.settings.Utils;
501f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport com.android.settings.deviceinfo.StorageWizardMoveConfirm;
51ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shankaimport com.android.settingslib.RestrictedLockUtils;
5267cd6ab93a526fe65877743e458590f4e6f187eeTony Mantlerimport com.android.settingslib.applications.ApplicationsState.Callbacks;
533344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishiimport com.android.settingslib.applications.StorageStatsSource;
543344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishiimport com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
551f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
561f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport java.util.Collections;
571f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport java.util.List;
5808703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport java.util.Map;
591f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport java.util.Objects;
6008703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport java.util.TreeMap;
61cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
628f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritzeimport static android.content.pm.ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
638f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritzeimport static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
648f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze
6560a09ea2388db01a661beeb9995a7ecf770a4200Jason Monkpublic class AppStorageSettings extends AppInfoWithHeader
663344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        implements OnClickListener, Callbacks, DialogInterface.OnClickListener,
673344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        LoaderManager.LoaderCallbacks<AppStorageStats> {
68588a0881c13d8ed63ba67b3145254c22211a2019Jason Monk    private static final String TAG = AppStorageSettings.class.getSimpleName();
69cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
70cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    //internal constants used in Handler
71cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int OP_SUCCESSFUL = 1;
72cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int OP_FAILED = 2;
73cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int MSG_CLEAR_USER_DATA = 1;
74cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int MSG_CLEAR_CACHE = 3;
75cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
76cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    // invalid size value used initially and also when size retrieval through PackageManager
77cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    // fails for whatever reason
78cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int SIZE_INVALID = -1;
79cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
80cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    // Result code identifiers
81cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    public static final int REQUEST_MANAGE_SPACE = 2;
82cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
83cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int DLG_CLEAR_DATA = DLG_BASE + 1;
84cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 2;
85cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
86e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private static final String KEY_STORAGE_USED = "storage_used";
87e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private static final String KEY_CHANGE_STORAGE = "change_storage_button";
88bd45c3cbe0ccb9d5a1ebeabccda1e803d613e729Jason Monk    private static final String KEY_STORAGE_SPACE = "storage_space";
89c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_STORAGE_CATEGORY = "storage_category";
9060a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk
91c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_TOTAL_SIZE = "total_size";
92c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_APP_SIZE = "app_size";
93c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_DATA_SIZE = "data_size";
94c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private static final String KEY_CACHE_SIZE = "cache_size";
95c27f9e179adef2061e0000385f350874a7772c4eJason Monk
96e7202b5c3d4deebf236bcfd435d7a7eecc254ab5Daniel Nishi    private static final String KEY_HEADER_BUTTONS = "header_view";
97c27f9e179adef2061e0000385f350874a7772c4eJason Monk
9808703c8bb19b518214bc352199bd46baab597547Felipe Leme    private static final String KEY_URI_CATEGORY = "uri_category";
9908703c8bb19b518214bc352199bd46baab597547Felipe Leme    private static final String KEY_CLEAR_URI = "clear_uri_button";
10008703c8bb19b518214bc352199bd46baab597547Felipe Leme
1011359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi    private static final String KEY_CACHE_CLEARED = "cache_cleared";
102278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi    private static final String KEY_DATA_CLEARED = "data_cleared";
1031359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi
104cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    // Views related to cache info
105c27f9e179adef2061e0000385f350874a7772c4eJason Monk    private Preference mCacheSize;
106cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private Button mClearDataButton;
107cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private Button mClearCacheButton;
10860a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk
109e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private Preference mStorageUsed;
110e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private Button mChangeStorageButton;
111cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
11208703c8bb19b518214bc352199bd46baab597547Felipe Leme    // Views related to URI permissions
11308703c8bb19b518214bc352199bd46baab597547Felipe Leme    private Button mClearUriButton;
11408703c8bb19b518214bc352199bd46baab597547Felipe Leme    private LayoutPreference mClearUri;
11508703c8bb19b518214bc352199bd46baab597547Felipe Leme    private PreferenceCategory mUri;
11608703c8bb19b518214bc352199bd46baab597547Felipe Leme
117cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private boolean mCanClearData = true;
1181359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi    private boolean mCacheCleared;
119278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi    private boolean mDataCleared;
120cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
1216a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi    private AppStorageSizesController mSizeController;
122cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
123cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private ClearCacheObserver mClearCacheObserver;
124cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private ClearUserDataObserver mClearDataObserver;
125cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
126e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private VolumeInfo[] mCandidates;
127e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private AlertDialog.Builder mDialogBuilder;
1283344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    private ApplicationInfo mInfo;
129e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk
130cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
131cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    public void onCreate(Bundle savedInstanceState) {
132cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        super.onCreate(savedInstanceState);
1331359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi        if (savedInstanceState != null) {
1341359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi            mCacheCleared = savedInstanceState.getBoolean(KEY_CACHE_CLEARED, false);
135278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi            mDataCleared = savedInstanceState.getBoolean(KEY_DATA_CLEARED, false);
136278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi            mCacheCleared = mCacheCleared || mDataCleared;
1371359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi        }
138cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
13960a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk        addPreferencesFromResource(R.xml.app_storage_settings);
14060a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk        setupViews();
141b7a7158b18147afbeacca604788e28d0d1209b07Jason Monk        initMoveDialog();
142cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
143cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
144ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk    @Override
145ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk    public void onResume() {
146ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk        super.onResume();
1473344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        updateSize();
148ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk    }
149ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk
1501359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi    @Override
1511359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi    public void onSaveInstanceState(Bundle outState) {
1521359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi        super.onSaveInstanceState(outState);
1531359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi        outState.putBoolean(KEY_CACHE_CLEARED, mCacheCleared);
154278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi        outState.putBoolean(KEY_DATA_CLEARED, mDataCleared);
1551359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi    }
1561359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi
15760a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk    private void setupViews() {
158cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        // Set default values on sizes
1596a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi        mSizeController = new AppStorageSizesController.Builder()
1606a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .setTotalSizePreference(findPreference(KEY_TOTAL_SIZE))
1616a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .setAppSizePreference(findPreference(KEY_APP_SIZE))
1626a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .setDataSizePreference(findPreference(KEY_DATA_SIZE))
1636a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .setCacheSizePreference(findPreference(KEY_CACHE_SIZE))
1646a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .setComputingString(R.string.computing_size)
1656a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .setErrorString(R.string.invalid_size_value)
1666a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi                .build();
1676a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi
168e7202b5c3d4deebf236bcfd435d7a7eecc254ab5Daniel Nishi        mClearDataButton = (Button) ((LayoutPreference) findPreference(KEY_HEADER_BUTTONS))
169e7202b5c3d4deebf236bcfd435d7a7eecc254ab5Daniel Nishi                .findViewById(R.id.left_button);
170cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
171e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mStorageUsed = findPreference(KEY_STORAGE_USED);
172e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mChangeStorageButton = (Button) ((LayoutPreference) findPreference(KEY_CHANGE_STORAGE))
173e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                .findViewById(R.id.button);
174e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mChangeStorageButton.setText(R.string.change);
175e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mChangeStorageButton.setOnClickListener(this);
176cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
177cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        // Cache section
178c27f9e179adef2061e0000385f350874a7772c4eJason Monk        mCacheSize = findPreference(KEY_CACHE_SIZE);
179e7202b5c3d4deebf236bcfd435d7a7eecc254ab5Daniel Nishi        mClearCacheButton = (Button) ((LayoutPreference) findPreference(KEY_HEADER_BUTTONS))
180e7202b5c3d4deebf236bcfd435d7a7eecc254ab5Daniel Nishi                .findViewById(R.id.right_button);
18160a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk        mClearCacheButton.setText(R.string.clear_cache_btn_text);
18208703c8bb19b518214bc352199bd46baab597547Felipe Leme
18308703c8bb19b518214bc352199bd46baab597547Felipe Leme        // URI permissions section
18408703c8bb19b518214bc352199bd46baab597547Felipe Leme        mUri = (PreferenceCategory) findPreference(KEY_URI_CATEGORY);
18508703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUri = (LayoutPreference) mUri.findPreference(KEY_CLEAR_URI);
18608703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUriButton = (Button) mClearUri.findViewById(R.id.button);
18708703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUriButton.setText(R.string.clear_uri_btn_text);
18808703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUriButton.setOnClickListener(this);
189cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
190cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
191cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
192cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    public void onClick(View v) {
193cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (v == mClearCacheButton) {
1949e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka            if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) {
195ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
196ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                        getActivity(), mAppsControlDisallowedAdmin);
197ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                return;
198ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka            } else if (mClearCacheObserver == null) { // Lazy initialization of observer
199cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mClearCacheObserver = new ClearCacheObserver();
200cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
201c49ab99007d74edf7086e8254cb6812771313b52Fan Zhang            mMetricsFeatureProvider.action(getContext(),
202c49ab99007d74edf7086e8254cb6812771313b52Fan Zhang                    MetricsEvent.ACTION_SETTINGS_CLEAR_APP_CACHE);
203cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mPm.deleteApplicationCacheFiles(mPackageName, mClearCacheObserver);
204e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        } else if (v == mClearDataButton) {
2059e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka            if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) {
206ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
207ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                        getActivity(), mAppsControlDisallowedAdmin);
208ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka            } else if (mAppEntry.info.manageSpaceActivityName != null) {
209cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                if (!Utils.isMonkeyRunning()) {
210cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    Intent intent = new Intent(Intent.ACTION_DEFAULT);
211cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    intent.setClassName(mAppEntry.info.packageName,
212cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            mAppEntry.info.manageSpaceActivityName);
213cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    startActivityForResult(intent, REQUEST_MANAGE_SPACE);
214cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                }
215cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            } else {
216cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                showDialogInner(DLG_CLEAR_DATA, 0);
217cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
21816634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey        } else if (v == mChangeStorageButton && mDialogBuilder != null && !isMoveInProgress()) {
219e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            mDialogBuilder.show();
22008703c8bb19b518214bc352199bd46baab597547Felipe Leme        } else if (v == mClearUriButton) {
2219e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka            if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) {
222ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
223ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                        getActivity(), mAppsControlDisallowedAdmin);
224ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka            } else {
225ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka                clearUriPermissions();
226ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka            }
22760a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk        }
22860a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk    }
22960a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk
23016634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey    private boolean isMoveInProgress() {
23116634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey        try {
23216634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey            // TODO: define a cleaner API for this
2339e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey            AppGlobals.getPackageManager().checkPackageStartable(mPackageName,
2349e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey                    UserHandle.myUserId());
23516634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey            return false;
2369e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey        } catch (RemoteException | SecurityException e) {
2379e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey            return true;
23816634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey        }
23916634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey    }
24016634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey
24160a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk    @Override
242e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    public void onClick(DialogInterface dialog, int which) {
2431f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final Context context = getActivity();
2441f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
2451f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        // If not current volume, kick off move wizard
246e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        final VolumeInfo targetVol = mCandidates[which];
247954d8dad5e395544f95ca211466bcc7195d31877Jeff Sharkey        final VolumeInfo currentVol = context.getPackageManager().getPackageCurrentVolume(
2481f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey                mAppEntry.info);
2491f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        if (!Objects.equals(targetVol, currentVol)) {
2501f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey            final Intent intent = new Intent(context, StorageWizardMoveConfirm.class);
2511f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey            intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, targetVol.getId());
2521f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey            intent.putExtra(Intent.EXTRA_PACKAGE_NAME, mAppEntry.info.packageName);
2531f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey            startActivity(intent);
254cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
255e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        dialog.dismiss();
256cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
257cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
258cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
259cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    protected boolean refreshUi() {
260cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        retrieveAppEntry();
2619a1c0dce7a496f51087cf0497b931a31c64b0a65Julia Reynolds        if (mAppEntry == null) {
2629a1c0dce7a496f51087cf0497b931a31c64b0a65Julia Reynolds            return false;
2639a1c0dce7a496f51087cf0497b931a31c64b0a65Julia Reynolds        }
264e7202b5c3d4deebf236bcfd435d7a7eecc254ab5Daniel Nishi        updateUiWithSize(mSizeController.getLastResult());
26508703c8bb19b518214bc352199bd46baab597547Felipe Leme        refreshGrantedUriPermissions();
2661f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
2671f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final VolumeInfo currentVol = getActivity().getPackageManager()
268954d8dad5e395544f95ca211466bcc7195d31877Jeff Sharkey                .getPackageCurrentVolume(mAppEntry.info);
269e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        final StorageManager storage = getContext().getSystemService(StorageManager.class);
270e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        mStorageUsed.setSummary(storage.getBestVolumeDescription(currentVol));
271e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk
272e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        refreshButtons();
2731f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
274cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        return true;
275cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
276cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
277cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private void refreshButtons() {
278e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk        initMoveDialog();
2791f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        initDataButtons();
280cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
281cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
282cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private void initDataButtons() {
2838f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        final boolean appHasSpaceManagementUI = mAppEntry.info.manageSpaceActivityName != null;
2848f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        final boolean appHasActiveAdmins = mDpm.packageHasActiveAdmins(mPackageName);
2858f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        // Check that SYSTEM_APP flag is set, and ALLOW_CLEAR_USER_DATA is not set.
2868f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        final boolean isNonClearableSystemApp =
2878f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze                (mAppEntry.info.flags & (FLAG_SYSTEM | FLAG_ALLOW_CLEAR_USER_DATA)) == FLAG_SYSTEM;
2888f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        final boolean appRestrictsClearingData = isNonClearableSystemApp || appHasActiveAdmins;
2898f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze
2908f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        final Intent intent = new Intent(Intent.ACTION_DEFAULT);
2918f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        if (appHasSpaceManagementUI) {
2928f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze            intent.setClassName(mAppEntry.info.packageName, mAppEntry.info.manageSpaceActivityName);
2938f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        }
2948f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        final boolean isManageSpaceActivityAvailable =
2958f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze                getPackageManager().resolveActivity(intent, 0) != null;
2968f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze
2978f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze        if ((!appHasSpaceManagementUI && appRestrictsClearingData)
2988f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze                || !isManageSpaceActivityAvailable) {
299cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataButton.setText(R.string.clear_user_data_text);
300cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataButton.setEnabled(false);
301cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mCanClearData = false;
302cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        } else {
3038f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze            if (appHasSpaceManagementUI) {
304cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mClearDataButton.setText(R.string.manage_space_text);
305cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            } else {
306cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                mClearDataButton.setText(R.string.clear_user_data_text);
307cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
308cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataButton.setOnClickListener(this);
309cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
3109e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka
3119e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka        if (mAppsControlDisallowedBySystem) {
3129e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka            mClearDataButton.setEnabled(false);
3139e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka        }
314cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
315cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
316e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk    private void initMoveDialog() {
3171f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final Context context = getActivity();
3181f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final StorageManager storage = context.getSystemService(StorageManager.class);
3191f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
3201f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey        final List<VolumeInfo> candidates = context.getPackageManager()
321954d8dad5e395544f95ca211466bcc7195d31877Jeff Sharkey                .getPackageCandidateVolumes(mAppEntry.info);
322c27f9e179adef2061e0000385f350874a7772c4eJason Monk        if (candidates.size() > 1) {
323c27f9e179adef2061e0000385f350874a7772c4eJason Monk            Collections.sort(candidates, VolumeInfo.getDescriptionComparator());
3241f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey
325e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            CharSequence[] labels = new CharSequence[candidates.size()];
326e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            int current = -1;
327e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            for (int i = 0; i < candidates.size(); i++) {
328e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                final String volDescrip = storage.getBestVolumeDescription(candidates.get(i));
329e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                if (Objects.equals(volDescrip, mStorageUsed.getSummary())) {
330e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                    current = i;
331e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                }
332e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                labels[i] = volDescrip;
333c27f9e179adef2061e0000385f350874a7772c4eJason Monk            }
334e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            mCandidates = candidates.toArray(new VolumeInfo[candidates.size()]);
335e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            mDialogBuilder = new AlertDialog.Builder(getContext())
336e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                    .setTitle(R.string.change_storage)
337e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                    .setSingleChoiceItems(labels, current, this)
338e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk                    .setNegativeButton(R.string.cancel, null);
339c27f9e179adef2061e0000385f350874a7772c4eJason Monk        } else {
340e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            removePreference(KEY_STORAGE_USED);
341e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk            removePreference(KEY_CHANGE_STORAGE);
342bd45c3cbe0ccb9d5a1ebeabccda1e803d613e729Jason Monk            removePreference(KEY_STORAGE_SPACE);
343cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
344cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
345cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
346cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    /*
347cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     * Private method to initiate clearing user data when the user clicks the clear data
348cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     * button for a system package
349cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     */
350cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private void initiateClearUserData() {
351c49ab99007d74edf7086e8254cb6812771313b52Fan Zhang        mMetricsFeatureProvider.action(getContext(), MetricsEvent.ACTION_SETTINGS_CLEAR_APP_DATA);
352cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        mClearDataButton.setEnabled(false);
353cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        // Invoke uninstall or clear user data based on sysPackage
354cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        String packageName = mAppEntry.info.packageName;
355cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        Log.i(TAG, "Clearing user data for package : " + packageName);
356cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (mClearDataObserver == null) {
357cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataObserver = new ClearUserDataObserver();
358cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
359cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        ActivityManager am = (ActivityManager)
360cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                getActivity().getSystemService(Context.ACTIVITY_SERVICE);
361cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        boolean res = am.clearApplicationUserData(packageName, mClearDataObserver);
362cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        if (!res) {
363cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            // Clearing data failed for some obscure reason. Just log error for now
364cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            Log.i(TAG, "Couldnt clear application user data for package:"+packageName);
365cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            showDialogInner(DLG_CANNOT_CLEAR_DATA, 0);
366cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        } else {
367cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataButton.setText(R.string.recompute_size);
368cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
369cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
370cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
371cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    /*
372cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     * Private method to handle clear message notification from observer when
373cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     * the async operation from PackageManager is complete
374cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk     */
375cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private void processClearMsg(Message msg) {
376cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        int result = msg.arg1;
377cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        String packageName = mAppEntry.info.packageName;
378cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        mClearDataButton.setText(R.string.clear_user_data_text);
37960a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk        if (result == OP_SUCCESSFUL) {
380cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            Log.i(TAG, "Cleared user data for package : "+packageName);
3813344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            updateSize();
382cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        } else {
383cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mClearDataButton.setEnabled(true);
384cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
385cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
386cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
38708703c8bb19b518214bc352199bd46baab597547Felipe Leme    private void refreshGrantedUriPermissions() {
38808703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Clear UI first (in case the activity has been resumed)
38908703c8bb19b518214bc352199bd46baab597547Felipe Leme        removeUriPermissionsFromUi();
39008703c8bb19b518214bc352199bd46baab597547Felipe Leme
39108703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Gets all URI permissions from am.
39208703c8bb19b518214bc352199bd46baab597547Felipe Leme        ActivityManager am = (ActivityManager) getActivity().getSystemService(
39308703c8bb19b518214bc352199bd46baab597547Felipe Leme                Context.ACTIVITY_SERVICE);
39408703c8bb19b518214bc352199bd46baab597547Felipe Leme        List<UriPermission> perms =
39508703c8bb19b518214bc352199bd46baab597547Felipe Leme                am.getGrantedUriPermissions(mAppEntry.info.packageName).getList();
39608703c8bb19b518214bc352199bd46baab597547Felipe Leme
39708703c8bb19b518214bc352199bd46baab597547Felipe Leme        if (perms.isEmpty()) {
39808703c8bb19b518214bc352199bd46baab597547Felipe Leme            mClearUriButton.setVisibility(View.GONE);
39908703c8bb19b518214bc352199bd46baab597547Felipe Leme            return;
40008703c8bb19b518214bc352199bd46baab597547Felipe Leme        }
40108703c8bb19b518214bc352199bd46baab597547Felipe Leme
40208703c8bb19b518214bc352199bd46baab597547Felipe Leme        PackageManager pm = getActivity().getPackageManager();
40308703c8bb19b518214bc352199bd46baab597547Felipe Leme
40408703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Group number of URIs by app.
40508703c8bb19b518214bc352199bd46baab597547Felipe Leme        Map<CharSequence, MutableInt> uriCounters = new TreeMap<>();
40608703c8bb19b518214bc352199bd46baab597547Felipe Leme        for (UriPermission perm : perms) {
40708703c8bb19b518214bc352199bd46baab597547Felipe Leme            String authority = perm.getUri().getAuthority();
40808703c8bb19b518214bc352199bd46baab597547Felipe Leme            ProviderInfo provider = pm.resolveContentProvider(authority, 0);
40908703c8bb19b518214bc352199bd46baab597547Felipe Leme            CharSequence app = provider.applicationInfo.loadLabel(pm);
41008703c8bb19b518214bc352199bd46baab597547Felipe Leme            MutableInt count = uriCounters.get(app);
41108703c8bb19b518214bc352199bd46baab597547Felipe Leme            if (count == null) {
41208703c8bb19b518214bc352199bd46baab597547Felipe Leme                uriCounters.put(app, new MutableInt(1));
41308703c8bb19b518214bc352199bd46baab597547Felipe Leme            } else {
41408703c8bb19b518214bc352199bd46baab597547Felipe Leme                count.value++;
41508703c8bb19b518214bc352199bd46baab597547Felipe Leme            }
41608703c8bb19b518214bc352199bd46baab597547Felipe Leme        }
41708703c8bb19b518214bc352199bd46baab597547Felipe Leme
41808703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Dynamically add the preferences, one per app.
41908703c8bb19b518214bc352199bd46baab597547Felipe Leme        int order = 0;
42008703c8bb19b518214bc352199bd46baab597547Felipe Leme        for (Map.Entry<CharSequence, MutableInt> entry : uriCounters.entrySet()) {
42108703c8bb19b518214bc352199bd46baab597547Felipe Leme            int numberResources = entry.getValue().value;
42208703c8bb19b518214bc352199bd46baab597547Felipe Leme            Preference pref = new Preference(getPrefContext());
42308703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setTitle(entry.getKey());
42408703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setSummary(getPrefContext().getResources()
42508703c8bb19b518214bc352199bd46baab597547Felipe Leme                    .getQuantityString(R.plurals.uri_permissions_text, numberResources,
42608703c8bb19b518214bc352199bd46baab597547Felipe Leme                            numberResources));
42708703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setSelectable(false);
42808703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setLayoutResource(R.layout.horizontal_preference);
42908703c8bb19b518214bc352199bd46baab597547Felipe Leme            pref.setOrder(order);
43008703c8bb19b518214bc352199bd46baab597547Felipe Leme            Log.v(TAG, "Adding preference '" + pref + "' at order " + order);
43108703c8bb19b518214bc352199bd46baab597547Felipe Leme            mUri.addPreference(pref);
43208703c8bb19b518214bc352199bd46baab597547Felipe Leme        }
43308703c8bb19b518214bc352199bd46baab597547Felipe Leme
4349e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka        if (mAppsControlDisallowedBySystem) {
4359e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka            mClearUriButton.setEnabled(false);
4369e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka        }
4379e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka
43808703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUri.setOrder(order);
43908703c8bb19b518214bc352199bd46baab597547Felipe Leme        mClearUriButton.setVisibility(View.VISIBLE);
44008703c8bb19b518214bc352199bd46baab597547Felipe Leme
44108703c8bb19b518214bc352199bd46baab597547Felipe Leme    }
44208703c8bb19b518214bc352199bd46baab597547Felipe Leme
44308703c8bb19b518214bc352199bd46baab597547Felipe Leme    private void clearUriPermissions() {
44408703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Synchronously revoke the permissions.
44508703c8bb19b518214bc352199bd46baab597547Felipe Leme        final ActivityManager am = (ActivityManager) getActivity().getSystemService(
44608703c8bb19b518214bc352199bd46baab597547Felipe Leme                Context.ACTIVITY_SERVICE);
44708703c8bb19b518214bc352199bd46baab597547Felipe Leme        am.clearGrantedUriPermissions(mAppEntry.info.packageName);
44808703c8bb19b518214bc352199bd46baab597547Felipe Leme
44908703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Update UI
45008703c8bb19b518214bc352199bd46baab597547Felipe Leme        refreshGrantedUriPermissions();
45108703c8bb19b518214bc352199bd46baab597547Felipe Leme    }
45208703c8bb19b518214bc352199bd46baab597547Felipe Leme
45308703c8bb19b518214bc352199bd46baab597547Felipe Leme    private void removeUriPermissionsFromUi() {
45408703c8bb19b518214bc352199bd46baab597547Felipe Leme        // Remove all preferences but the clear button.
45508703c8bb19b518214bc352199bd46baab597547Felipe Leme        int count = mUri.getPreferenceCount();
45608703c8bb19b518214bc352199bd46baab597547Felipe Leme        for (int i = count - 1; i >= 0; i--) {
45708703c8bb19b518214bc352199bd46baab597547Felipe Leme            Preference pref = mUri.getPreference(i);
45808703c8bb19b518214bc352199bd46baab597547Felipe Leme            if (pref != mClearUri) {
45908703c8bb19b518214bc352199bd46baab597547Felipe Leme                mUri.removePreference(pref);
46008703c8bb19b518214bc352199bd46baab597547Felipe Leme            }
46108703c8bb19b518214bc352199bd46baab597547Felipe Leme        }
46208703c8bb19b518214bc352199bd46baab597547Felipe Leme    }
46308703c8bb19b518214bc352199bd46baab597547Felipe Leme
464cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
465cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    protected AlertDialog createDialog(int id, int errorCode) {
466cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        switch (id) {
467cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            case DLG_CLEAR_DATA:
468cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                return new AlertDialog.Builder(getActivity())
469cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setTitle(getActivity().getText(R.string.clear_data_dlg_title))
470cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setMessage(getActivity().getText(R.string.clear_data_dlg_text))
471cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
472cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            public void onClick(DialogInterface dialog, int which) {
473cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                // Clear user data here
474cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                initiateClearUserData();
475cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            }
476cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        })
477cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setNegativeButton(R.string.dlg_cancel, null)
478cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .create();
479cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            case DLG_CANNOT_CLEAR_DATA:
480cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                return new AlertDialog.Builder(getActivity())
481cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setTitle(getActivity().getText(R.string.clear_failed_dlg_title))
482cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setMessage(getActivity().getText(R.string.clear_failed_dlg_text))
483cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .setNeutralButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
484cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            public void onClick(DialogInterface dialog, int which) {
485cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                mClearDataButton.setEnabled(false);
486cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                //force to recompute changed value
487cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                                setIntentAndFinish(false, false);
488cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                            }
489cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        })
490cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                        .create();
491cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
492cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        return null;
493cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
494cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
495cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    @Override
496cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    public void onPackageSizeChanged(String packageName) {
4973344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    }
4983344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
4993344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    @Override
5003344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    public Loader<AppStorageStats> onCreateLoader(int id, Bundle args) {
5013344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        Context context = getContext();
5023344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        return new FetchPackageStorageAsyncLoader(
5033344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi                context, new StorageStatsSource(context), mInfo, UserHandle.of(mUserId));
5043344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    }
5053344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5063344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    @Override
5073344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    public void onLoadFinished(Loader<AppStorageStats> loader, AppStorageStats result) {
5086a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi        mSizeController.setResult(result);
5093344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        updateUiWithSize(result);
5103344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    }
5113344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5123344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    @Override
5133344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    public void onLoaderReset(Loader<AppStorageStats> loader) {
5143344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    }
5153344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5163344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    private void updateSize() {
5173344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        PackageManager packageManager = getPackageManager();
5183344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        try {
5193344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            mInfo = packageManager.getApplicationInfo(mPackageName, 0);
5203344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        } catch (PackageManager.NameNotFoundException e) {
5213344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            Log.e(TAG, "Could not find package", e);
5223344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        }
5233344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5243344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        if (mInfo == null) {
5253344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            return;
5263344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        }
5273344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5283344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        getLoaderManager().restartLoader(1, Bundle.EMPTY, this);
5293344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    }
5303344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
5313344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi    private void updateUiWithSize(AppStorageStats result) {
5321359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi        if (mCacheCleared) {
5331359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi            mSizeController.setCacheCleared(true);
5341359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi        }
535278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi        if (mDataCleared) {
536278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi            mSizeController.setDataCleared(true);
537278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi        }
5381359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi
5396a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi        mSizeController.updateUi(getContext());
5406a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi
5413344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        if (result == null) {
5423344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            mClearDataButton.setEnabled(false);
5433344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            mClearCacheButton.setEnabled(false);
5443344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        } else {
5453344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            long codeSize = result.getCodeBytes();
5463344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            long dataSize = result.getDataBytes();
5473344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            long cacheSize = result.getCacheBytes();
5483344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi
549278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi            if (dataSize <= 0 || !mCanClearData || mDataCleared) {
5503344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi                mClearDataButton.setEnabled(false);
5513344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            } else {
5523344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi                mClearDataButton.setEnabled(true);
5533344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi                mClearDataButton.setOnClickListener(this);
5543344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            }
5551359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi            if (cacheSize <= 0 || mCacheCleared) {
5563344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi                mClearCacheButton.setEnabled(false);
5573344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            } else {
5583344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi                mClearCacheButton.setEnabled(true);
5593344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi                mClearCacheButton.setOnClickListener(this);
5603344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            }
5613344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        }
5623344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi        if (mAppsControlDisallowedBySystem) {
5633344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            mClearCacheButton.setEnabled(false);
5643344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi            mClearDataButton.setEnabled(false);
565cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
566cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
567cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
568cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    private final Handler mHandler = new Handler() {
569cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        public void handleMessage(Message msg) {
570cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            if (getView() == null) {
571cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                return;
572cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
573cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            switch (msg.what) {
574cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                case MSG_CLEAR_USER_DATA:
575278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi                    mDataCleared = true;
576278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi                    mCacheCleared = true;
577cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    processClearMsg(msg);
578cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    break;
579cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                case MSG_CLEAR_CACHE:
5801359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi                    mCacheCleared = true;
581cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    // Refresh size info
5823344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi                    updateSize();
583cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk                    break;
584cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            }
585cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
586cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    };
587cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
5888a963babe2e36b7a41f77b8d2598c97658196e58Chris Wren    @Override
5896507613ebcd22e4691c2af92a5c161bd327db336Fan Zhang    public int getMetricsCategory() {
5909d1bfd1e8de6e46137a9571507c03526880d6a46Chris Wren        return MetricsEvent.APPLICATIONS_APP_STORAGE;
5918a963babe2e36b7a41f77b8d2598c97658196e58Chris Wren    }
5928a963babe2e36b7a41f77b8d2598c97658196e58Chris Wren
593cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    class ClearCacheObserver extends IPackageDataObserver.Stub {
594cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        public void onRemoveCompleted(final String packageName, final boolean succeeded) {
595cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            final Message msg = mHandler.obtainMessage(MSG_CLEAR_CACHE);
596cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            msg.arg1 = succeeded ? OP_SUCCESSFUL : OP_FAILED;
597cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk            mHandler.sendMessage(msg);
598cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
599cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
600cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk
601cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    class ClearUserDataObserver extends IPackageDataObserver.Stub {
602cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk       public void onRemoveCompleted(final String packageName, final boolean succeeded) {
603cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk           final Message msg = mHandler.obtainMessage(MSG_CLEAR_USER_DATA);
60460a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk           msg.arg1 = succeeded ? OP_SUCCESSFUL : OP_FAILED;
605cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk           mHandler.sendMessage(msg);
606cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk        }
607cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk    }
608cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk}
609