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; 2120c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Lemeimport static android.os.storage.StorageVolume.ScopedAccessProviderContract.AUTHORITY; 2220c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Lemeimport static android.os.storage.StorageVolume.ScopedAccessProviderContract.COL_GRANTED; 2320c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Lemeimport static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS; 2420c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Leme 2520c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Lemeimport static com.android.settings.applications.AppStateDirectoryAccessBridge.DEBUG; 26ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang 27cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.app.ActivityManager; 28cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.app.AlertDialog; 2916634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkeyimport android.app.AppGlobals; 30025883da78cdb0fbf70bcd3c2c2d32169c25c7f7Felipe Lemeimport android.app.GrantedUriPermission; 313344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishiimport android.app.LoaderManager; 3220c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Lemeimport android.content.ContentResolver; 3320c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Lemeimport android.content.ContentValues; 34cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.Context; 35cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.DialogInterface; 36cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.Intent; 373344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishiimport android.content.Loader; 38cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.pm.ApplicationInfo; 39cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.content.pm.IPackageDataObserver; 4008703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport android.content.pm.PackageManager; 4108703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport android.content.pm.ProviderInfo; 4220c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Lemeimport android.net.Uri; 43cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.os.Bundle; 44cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.os.Handler; 45cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.os.Message; 4616634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkeyimport android.os.RemoteException; 479e9f7d11162df92bc430002423a281e22176de41Jeff Sharkeyimport android.os.UserHandle; 481f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport android.os.storage.StorageManager; 491f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport android.os.storage.VolumeInfo; 50ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhangimport android.support.annotation.VisibleForTesting; 5139b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.support.v7.preference.Preference; 5239b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.support.v7.preference.PreferenceCategory; 53cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.util.Log; 5408703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport android.util.MutableInt; 55cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.view.View; 56cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.view.View.OnClickListener; 57cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport android.widget.Button; 58cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 59265d3c2a0c36251bf8a9f571d7239b6dd404d942Tamas Berghammerimport com.android.internal.logging.nano.MetricsProto.MetricsEvent; 60cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport com.android.settings.R; 61cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monkimport com.android.settings.Utils; 621f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport com.android.settings.deviceinfo.StorageWizardMoveConfirm; 63ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhangimport com.android.settings.widget.ActionButtonPreference; 64ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shankaimport com.android.settingslib.RestrictedLockUtils; 6567cd6ab93a526fe65877743e458590f4e6f187eeTony Mantlerimport com.android.settingslib.applications.ApplicationsState.Callbacks; 663344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishiimport com.android.settingslib.applications.StorageStatsSource; 673344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishiimport com.android.settingslib.applications.StorageStatsSource.AppStorageStats; 681f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey 691f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport java.util.Collections; 701f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport java.util.List; 7108703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport java.util.Map; 721f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkeyimport java.util.Objects; 7308703c8bb19b518214bc352199bd46baab597547Felipe Lemeimport java.util.TreeMap; 74cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 7560a09ea2388db01a661beeb9995a7ecf770a4200Jason Monkpublic class AppStorageSettings extends AppInfoWithHeader 763344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi implements OnClickListener, Callbacks, DialogInterface.OnClickListener, 773344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi LoaderManager.LoaderCallbacks<AppStorageStats> { 78588a0881c13d8ed63ba67b3145254c22211a2019Jason Monk private static final String TAG = AppStorageSettings.class.getSimpleName(); 79cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 80cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk //internal constants used in Handler 81cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk private static final int OP_SUCCESSFUL = 1; 82cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk private static final int OP_FAILED = 2; 83cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk private static final int MSG_CLEAR_USER_DATA = 1; 84cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk private static final int MSG_CLEAR_CACHE = 3; 85cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 86cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk // invalid size value used initially and also when size retrieval through PackageManager 87cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk // fails for whatever reason 88cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk private static final int SIZE_INVALID = -1; 89cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 90cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk // Result code identifiers 91cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk public static final int REQUEST_MANAGE_SPACE = 2; 92cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 93cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk private static final int DLG_CLEAR_DATA = DLG_BASE + 1; 94cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 2; 95cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 96e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk private static final String KEY_STORAGE_USED = "storage_used"; 97e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk private static final String KEY_CHANGE_STORAGE = "change_storage_button"; 98bd45c3cbe0ccb9d5a1ebeabccda1e803d613e729Jason Monk private static final String KEY_STORAGE_SPACE = "storage_space"; 99c27f9e179adef2061e0000385f350874a7772c4eJason Monk private static final String KEY_STORAGE_CATEGORY = "storage_category"; 10060a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk 101c27f9e179adef2061e0000385f350874a7772c4eJason Monk private static final String KEY_TOTAL_SIZE = "total_size"; 102c27f9e179adef2061e0000385f350874a7772c4eJason Monk private static final String KEY_APP_SIZE = "app_size"; 103c27f9e179adef2061e0000385f350874a7772c4eJason Monk private static final String KEY_DATA_SIZE = "data_size"; 104c27f9e179adef2061e0000385f350874a7772c4eJason Monk private static final String KEY_CACHE_SIZE = "cache_size"; 105c27f9e179adef2061e0000385f350874a7772c4eJason Monk 106e7202b5c3d4deebf236bcfd435d7a7eecc254ab5Daniel Nishi private static final String KEY_HEADER_BUTTONS = "header_view"; 107c27f9e179adef2061e0000385f350874a7772c4eJason Monk 10808703c8bb19b518214bc352199bd46baab597547Felipe Leme private static final String KEY_URI_CATEGORY = "uri_category"; 10908703c8bb19b518214bc352199bd46baab597547Felipe Leme private static final String KEY_CLEAR_URI = "clear_uri_button"; 11008703c8bb19b518214bc352199bd46baab597547Felipe Leme 1111359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi private static final String KEY_CACHE_CLEARED = "cache_cleared"; 112278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi private static final String KEY_DATA_CLEARED = "data_cleared"; 1131359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi 114cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk // Views related to cache info 115ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang @VisibleForTesting 116ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang ActionButtonPreference mButtonsPref; 11760a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk 118e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk private Preference mStorageUsed; 119e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk private Button mChangeStorageButton; 120cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 12108703c8bb19b518214bc352199bd46baab597547Felipe Leme // Views related to URI permissions 12208703c8bb19b518214bc352199bd46baab597547Felipe Leme private Button mClearUriButton; 12308703c8bb19b518214bc352199bd46baab597547Felipe Leme private LayoutPreference mClearUri; 12408703c8bb19b518214bc352199bd46baab597547Felipe Leme private PreferenceCategory mUri; 12508703c8bb19b518214bc352199bd46baab597547Felipe Leme 126cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk private boolean mCanClearData = true; 1271359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi private boolean mCacheCleared; 128278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi private boolean mDataCleared; 129cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 130ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang @VisibleForTesting 131ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang AppStorageSizesController mSizeController; 132cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 133cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk private ClearCacheObserver mClearCacheObserver; 134cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk private ClearUserDataObserver mClearDataObserver; 135cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 136e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk private VolumeInfo[] mCandidates; 137e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk private AlertDialog.Builder mDialogBuilder; 1383344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi private ApplicationInfo mInfo; 139e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk 140cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk @Override 141cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk public void onCreate(Bundle savedInstanceState) { 142cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk super.onCreate(savedInstanceState); 1431359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi if (savedInstanceState != null) { 1441359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi mCacheCleared = savedInstanceState.getBoolean(KEY_CACHE_CLEARED, false); 145278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi mDataCleared = savedInstanceState.getBoolean(KEY_DATA_CLEARED, false); 146278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi mCacheCleared = mCacheCleared || mDataCleared; 1471359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi } 148cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 14960a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk addPreferencesFromResource(R.xml.app_storage_settings); 15060a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk setupViews(); 151b7a7158b18147afbeacca604788e28d0d1209b07Jason Monk initMoveDialog(); 152cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 153cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 154ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk @Override 155ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk public void onResume() { 156ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk super.onResume(); 1573344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi updateSize(); 158ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk } 159ece9d5145f38ec077be9d7f3a2e145500b296a29Jason Monk 1601359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi @Override 1611359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi public void onSaveInstanceState(Bundle outState) { 1621359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi super.onSaveInstanceState(outState); 1631359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi outState.putBoolean(KEY_CACHE_CLEARED, mCacheCleared); 164278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi outState.putBoolean(KEY_DATA_CLEARED, mDataCleared); 1651359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi } 1661359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi 16760a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk private void setupViews() { 168cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk // Set default values on sizes 1696a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi mSizeController = new AppStorageSizesController.Builder() 1706a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi .setTotalSizePreference(findPreference(KEY_TOTAL_SIZE)) 1716a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi .setAppSizePreference(findPreference(KEY_APP_SIZE)) 1726a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi .setDataSizePreference(findPreference(KEY_DATA_SIZE)) 1736a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi .setCacheSizePreference(findPreference(KEY_CACHE_SIZE)) 1746a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi .setComputingString(R.string.computing_size) 1756a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi .setErrorString(R.string.invalid_size_value) 1766a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi .build(); 177ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mButtonsPref = ((ActionButtonPreference) findPreference(KEY_HEADER_BUTTONS)) 178ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang .setButton1Positive(false) 179ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang .setButton2Positive(false); 180cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 181e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk mStorageUsed = findPreference(KEY_STORAGE_USED); 182e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk mChangeStorageButton = (Button) ((LayoutPreference) findPreference(KEY_CHANGE_STORAGE)) 183e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk .findViewById(R.id.button); 184e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk mChangeStorageButton.setText(R.string.change); 185e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk mChangeStorageButton.setOnClickListener(this); 186cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 187cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk // Cache section 188ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mButtonsPref.setButton2Text(R.string.clear_cache_btn_text); 18908703c8bb19b518214bc352199bd46baab597547Felipe Leme 19008703c8bb19b518214bc352199bd46baab597547Felipe Leme // URI permissions section 19108703c8bb19b518214bc352199bd46baab597547Felipe Leme mUri = (PreferenceCategory) findPreference(KEY_URI_CATEGORY); 19208703c8bb19b518214bc352199bd46baab597547Felipe Leme mClearUri = (LayoutPreference) mUri.findPreference(KEY_CLEAR_URI); 19308703c8bb19b518214bc352199bd46baab597547Felipe Leme mClearUriButton = (Button) mClearUri.findViewById(R.id.button); 19408703c8bb19b518214bc352199bd46baab597547Felipe Leme mClearUriButton.setText(R.string.clear_uri_btn_text); 19508703c8bb19b518214bc352199bd46baab597547Felipe Leme mClearUriButton.setOnClickListener(this); 196cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 197cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 198ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang @VisibleForTesting 199ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang void handleClearCacheClick() { 200ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) { 201ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang RestrictedLockUtils.sendShowAdminSupportDetailsIntent( 202ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang getActivity(), mAppsControlDisallowedAdmin); 203ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang return; 204ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang } else if (mClearCacheObserver == null) { // Lazy initialization of observer 205ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mClearCacheObserver = new ClearCacheObserver(); 206ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang } 207ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mMetricsFeatureProvider.action(getContext(), 208ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang MetricsEvent.ACTION_SETTINGS_CLEAR_APP_CACHE); 209ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mPm.deleteApplicationCacheFiles(mPackageName, mClearCacheObserver); 210ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang } 211ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang 212ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang @VisibleForTesting 213ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang void handleClearDataClick() { 214ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) { 215ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang RestrictedLockUtils.sendShowAdminSupportDetailsIntent( 216ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang getActivity(), mAppsControlDisallowedAdmin); 217ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang } else if (mAppEntry.info.manageSpaceActivityName != null) { 218ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang if (!Utils.isMonkeyRunning()) { 219ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang Intent intent = new Intent(Intent.ACTION_DEFAULT); 220ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang intent.setClassName(mAppEntry.info.packageName, 221ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mAppEntry.info.manageSpaceActivityName); 222ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang startActivityForResult(intent, REQUEST_MANAGE_SPACE); 223ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang } 224ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang } else { 225ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang showDialogInner(DLG_CLEAR_DATA, 0); 226ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang } 227ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang } 228ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang 229cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk @Override 230cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk public void onClick(View v) { 231ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang if (v == mChangeStorageButton && mDialogBuilder != null && !isMoveInProgress()) { 232e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk mDialogBuilder.show(); 23308703c8bb19b518214bc352199bd46baab597547Felipe Leme } else if (v == mClearUriButton) { 2349e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) { 235ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka RestrictedLockUtils.sendShowAdminSupportDetailsIntent( 236ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka getActivity(), mAppsControlDisallowedAdmin); 237ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka } else { 238ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka clearUriPermissions(); 239ef550767b0b469534a94c293ea517a19778b58b0Sudheer Shanka } 24060a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk } 24160a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk } 24260a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk 24316634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey private boolean isMoveInProgress() { 24416634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey try { 24516634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey // TODO: define a cleaner API for this 2469e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey AppGlobals.getPackageManager().checkPackageStartable(mPackageName, 2479e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey UserHandle.myUserId()); 24816634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey return false; 2499e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey } catch (RemoteException | SecurityException e) { 2509e9f7d11162df92bc430002423a281e22176de41Jeff Sharkey return true; 25116634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey } 25216634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey } 25316634fd0ff74f243aa26ad4714df3a0921bdbe20Jeff Sharkey 25460a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk @Override 255e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk public void onClick(DialogInterface dialog, int which) { 2561f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey final Context context = getActivity(); 2571f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey 2581f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey // If not current volume, kick off move wizard 259e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk final VolumeInfo targetVol = mCandidates[which]; 260954d8dad5e395544f95ca211466bcc7195d31877Jeff Sharkey final VolumeInfo currentVol = context.getPackageManager().getPackageCurrentVolume( 2611f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey mAppEntry.info); 2621f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey if (!Objects.equals(targetVol, currentVol)) { 2631f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey final Intent intent = new Intent(context, StorageWizardMoveConfirm.class); 2641f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, targetVol.getId()); 2651f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey intent.putExtra(Intent.EXTRA_PACKAGE_NAME, mAppEntry.info.packageName); 2661f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey startActivity(intent); 267cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 268e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk dialog.dismiss(); 269cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 270cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 271cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk @Override 272cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk protected boolean refreshUi() { 273cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk retrieveAppEntry(); 2749a1c0dce7a496f51087cf0497b931a31c64b0a65Julia Reynolds if (mAppEntry == null) { 2759a1c0dce7a496f51087cf0497b931a31c64b0a65Julia Reynolds return false; 2769a1c0dce7a496f51087cf0497b931a31c64b0a65Julia Reynolds } 277e7202b5c3d4deebf236bcfd435d7a7eecc254ab5Daniel Nishi updateUiWithSize(mSizeController.getLastResult()); 27808703c8bb19b518214bc352199bd46baab597547Felipe Leme refreshGrantedUriPermissions(); 2791f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey 2801f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey final VolumeInfo currentVol = getActivity().getPackageManager() 281954d8dad5e395544f95ca211466bcc7195d31877Jeff Sharkey .getPackageCurrentVolume(mAppEntry.info); 282e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk final StorageManager storage = getContext().getSystemService(StorageManager.class); 283e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk mStorageUsed.setSummary(storage.getBestVolumeDescription(currentVol)); 284e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk 285e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk refreshButtons(); 2861f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey 287cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk return true; 288cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 289cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 290cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk private void refreshButtons() { 291e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk initMoveDialog(); 2921f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey initDataButtons(); 293cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 294cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 295cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk private void initDataButtons() { 2968f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze final boolean appHasSpaceManagementUI = mAppEntry.info.manageSpaceActivityName != null; 2978f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze final boolean appHasActiveAdmins = mDpm.packageHasActiveAdmins(mPackageName); 2988f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze // Check that SYSTEM_APP flag is set, and ALLOW_CLEAR_USER_DATA is not set. 2998f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze final boolean isNonClearableSystemApp = 3008f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze (mAppEntry.info.flags & (FLAG_SYSTEM | FLAG_ALLOW_CLEAR_USER_DATA)) == FLAG_SYSTEM; 3018f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze final boolean appRestrictsClearingData = isNonClearableSystemApp || appHasActiveAdmins; 3028f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze 3038f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze final Intent intent = new Intent(Intent.ACTION_DEFAULT); 3048f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze if (appHasSpaceManagementUI) { 3058f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze intent.setClassName(mAppEntry.info.packageName, mAppEntry.info.manageSpaceActivityName); 3068f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze } 3078f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze final boolean isManageSpaceActivityAvailable = 3088f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze getPackageManager().resolveActivity(intent, 0) != null; 3098f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze 3108f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze if ((!appHasSpaceManagementUI && appRestrictsClearingData) 3118f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze || !isManageSpaceActivityAvailable) { 312ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mButtonsPref 313ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang .setButton1Text(R.string.clear_user_data_text) 314ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang .setButton1Enabled(false); 315cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk mCanClearData = false; 316cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } else { 3178f17fcaa1dd85c816916ffbed3f66ad80c2bbf0aMatthew Fritze if (appHasSpaceManagementUI) { 318ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mButtonsPref.setButton1Text(R.string.manage_space_text); 319cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } else { 320ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mButtonsPref.setButton1Text(R.string.clear_user_data_text); 321cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 322ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mButtonsPref 323ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang .setButton1Text(R.string.clear_user_data_text) 324ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang .setButton1OnClickListener(v -> handleClearDataClick()); 325cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 3269e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka 3279e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka if (mAppsControlDisallowedBySystem) { 328ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mButtonsPref.setButton1Enabled(false); 3299e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka } 330cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 331cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 332e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk private void initMoveDialog() { 3331f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey final Context context = getActivity(); 3341f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey final StorageManager storage = context.getSystemService(StorageManager.class); 3351f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey 3361f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey final List<VolumeInfo> candidates = context.getPackageManager() 337954d8dad5e395544f95ca211466bcc7195d31877Jeff Sharkey .getPackageCandidateVolumes(mAppEntry.info); 338c27f9e179adef2061e0000385f350874a7772c4eJason Monk if (candidates.size() > 1) { 339c27f9e179adef2061e0000385f350874a7772c4eJason Monk Collections.sort(candidates, VolumeInfo.getDescriptionComparator()); 3401f4efd7360dea3038fe2096b1d4bccaae8e2a09fJeff Sharkey 341e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk CharSequence[] labels = new CharSequence[candidates.size()]; 342e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk int current = -1; 343e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk for (int i = 0; i < candidates.size(); i++) { 344e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk final String volDescrip = storage.getBestVolumeDescription(candidates.get(i)); 345e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk if (Objects.equals(volDescrip, mStorageUsed.getSummary())) { 346e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk current = i; 347e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk } 348e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk labels[i] = volDescrip; 349c27f9e179adef2061e0000385f350874a7772c4eJason Monk } 350e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk mCandidates = candidates.toArray(new VolumeInfo[candidates.size()]); 351e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk mDialogBuilder = new AlertDialog.Builder(getContext()) 352e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk .setTitle(R.string.change_storage) 353e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk .setSingleChoiceItems(labels, current, this) 354e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk .setNegativeButton(R.string.cancel, null); 355c27f9e179adef2061e0000385f350874a7772c4eJason Monk } else { 356e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk removePreference(KEY_STORAGE_USED); 357e8400c2fb78e80979b5190d4abc9685442cdfc25Jason Monk removePreference(KEY_CHANGE_STORAGE); 358bd45c3cbe0ccb9d5a1ebeabccda1e803d613e729Jason Monk removePreference(KEY_STORAGE_SPACE); 359cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 360cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 361cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 362cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk /* 363cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk * Private method to initiate clearing user data when the user clicks the clear data 364cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk * button for a system package 365cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk */ 366cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk private void initiateClearUserData() { 367c49ab99007d74edf7086e8254cb6812771313b52Fan Zhang mMetricsFeatureProvider.action(getContext(), MetricsEvent.ACTION_SETTINGS_CLEAR_APP_DATA); 368ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mButtonsPref.setButton1Enabled(false); 369cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk // Invoke uninstall or clear user data based on sysPackage 370cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk String packageName = mAppEntry.info.packageName; 371cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk Log.i(TAG, "Clearing user data for package : " + packageName); 372cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk if (mClearDataObserver == null) { 373cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk mClearDataObserver = new ClearUserDataObserver(); 374cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 375cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk ActivityManager am = (ActivityManager) 376cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk getActivity().getSystemService(Context.ACTIVITY_SERVICE); 377cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk boolean res = am.clearApplicationUserData(packageName, mClearDataObserver); 378cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk if (!res) { 379cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk // Clearing data failed for some obscure reason. Just log error for now 38020c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Leme Log.i(TAG, "Couldn't clear application user data for package:" + packageName); 381cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk showDialogInner(DLG_CANNOT_CLEAR_DATA, 0); 382cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } else { 383ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mButtonsPref.setButton1Text(R.string.recompute_size); 384cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 385cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 386cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 387cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk /* 388cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk * Private method to handle clear message notification from observer when 389cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk * the async operation from PackageManager is complete 390cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk */ 391cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk private void processClearMsg(Message msg) { 392cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk int result = msg.arg1; 393cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk String packageName = mAppEntry.info.packageName; 394ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mButtonsPref.setButton1Text(R.string.clear_user_data_text); 39560a09ea2388db01a661beeb9995a7ecf770a4200Jason Monk if (result == OP_SUCCESSFUL) { 396ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang Log.i(TAG, "Cleared user data for package : " + packageName); 3973344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi updateSize(); 398cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } else { 399ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mButtonsPref.setButton1Enabled(true); 400cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 401cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 402cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 40308703c8bb19b518214bc352199bd46baab597547Felipe Leme private void refreshGrantedUriPermissions() { 40408703c8bb19b518214bc352199bd46baab597547Felipe Leme // Clear UI first (in case the activity has been resumed) 40508703c8bb19b518214bc352199bd46baab597547Felipe Leme removeUriPermissionsFromUi(); 40608703c8bb19b518214bc352199bd46baab597547Felipe Leme 40708703c8bb19b518214bc352199bd46baab597547Felipe Leme // Gets all URI permissions from am. 40808703c8bb19b518214bc352199bd46baab597547Felipe Leme ActivityManager am = (ActivityManager) getActivity().getSystemService( 40908703c8bb19b518214bc352199bd46baab597547Felipe Leme Context.ACTIVITY_SERVICE); 410025883da78cdb0fbf70bcd3c2c2d32169c25c7f7Felipe Leme List<GrantedUriPermission> perms = 41108703c8bb19b518214bc352199bd46baab597547Felipe Leme am.getGrantedUriPermissions(mAppEntry.info.packageName).getList(); 41208703c8bb19b518214bc352199bd46baab597547Felipe Leme 41308703c8bb19b518214bc352199bd46baab597547Felipe Leme if (perms.isEmpty()) { 41408703c8bb19b518214bc352199bd46baab597547Felipe Leme mClearUriButton.setVisibility(View.GONE); 41508703c8bb19b518214bc352199bd46baab597547Felipe Leme return; 41608703c8bb19b518214bc352199bd46baab597547Felipe Leme } 41708703c8bb19b518214bc352199bd46baab597547Felipe Leme 41808703c8bb19b518214bc352199bd46baab597547Felipe Leme PackageManager pm = getActivity().getPackageManager(); 41908703c8bb19b518214bc352199bd46baab597547Felipe Leme 42008703c8bb19b518214bc352199bd46baab597547Felipe Leme // Group number of URIs by app. 42108703c8bb19b518214bc352199bd46baab597547Felipe Leme Map<CharSequence, MutableInt> uriCounters = new TreeMap<>(); 422025883da78cdb0fbf70bcd3c2c2d32169c25c7f7Felipe Leme for (GrantedUriPermission perm : perms) { 423025883da78cdb0fbf70bcd3c2c2d32169c25c7f7Felipe Leme String authority = perm.uri.getAuthority(); 42408703c8bb19b518214bc352199bd46baab597547Felipe Leme ProviderInfo provider = pm.resolveContentProvider(authority, 0); 42508703c8bb19b518214bc352199bd46baab597547Felipe Leme CharSequence app = provider.applicationInfo.loadLabel(pm); 42608703c8bb19b518214bc352199bd46baab597547Felipe Leme MutableInt count = uriCounters.get(app); 42708703c8bb19b518214bc352199bd46baab597547Felipe Leme if (count == null) { 42808703c8bb19b518214bc352199bd46baab597547Felipe Leme uriCounters.put(app, new MutableInt(1)); 42908703c8bb19b518214bc352199bd46baab597547Felipe Leme } else { 43008703c8bb19b518214bc352199bd46baab597547Felipe Leme count.value++; 43108703c8bb19b518214bc352199bd46baab597547Felipe Leme } 43208703c8bb19b518214bc352199bd46baab597547Felipe Leme } 43308703c8bb19b518214bc352199bd46baab597547Felipe Leme 43408703c8bb19b518214bc352199bd46baab597547Felipe Leme // Dynamically add the preferences, one per app. 43508703c8bb19b518214bc352199bd46baab597547Felipe Leme int order = 0; 43608703c8bb19b518214bc352199bd46baab597547Felipe Leme for (Map.Entry<CharSequence, MutableInt> entry : uriCounters.entrySet()) { 43708703c8bb19b518214bc352199bd46baab597547Felipe Leme int numberResources = entry.getValue().value; 43808703c8bb19b518214bc352199bd46baab597547Felipe Leme Preference pref = new Preference(getPrefContext()); 43908703c8bb19b518214bc352199bd46baab597547Felipe Leme pref.setTitle(entry.getKey()); 44008703c8bb19b518214bc352199bd46baab597547Felipe Leme pref.setSummary(getPrefContext().getResources() 44108703c8bb19b518214bc352199bd46baab597547Felipe Leme .getQuantityString(R.plurals.uri_permissions_text, numberResources, 44208703c8bb19b518214bc352199bd46baab597547Felipe Leme numberResources)); 44308703c8bb19b518214bc352199bd46baab597547Felipe Leme pref.setSelectable(false); 44408703c8bb19b518214bc352199bd46baab597547Felipe Leme pref.setLayoutResource(R.layout.horizontal_preference); 44508703c8bb19b518214bc352199bd46baab597547Felipe Leme pref.setOrder(order); 44608703c8bb19b518214bc352199bd46baab597547Felipe Leme Log.v(TAG, "Adding preference '" + pref + "' at order " + order); 44708703c8bb19b518214bc352199bd46baab597547Felipe Leme mUri.addPreference(pref); 44808703c8bb19b518214bc352199bd46baab597547Felipe Leme } 44908703c8bb19b518214bc352199bd46baab597547Felipe Leme 4509e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka if (mAppsControlDisallowedBySystem) { 4519e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka mClearUriButton.setEnabled(false); 4529e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka } 4539e9e63b7b3b31fcae7242eb07f528487e0913402Sudheer Shanka 45408703c8bb19b518214bc352199bd46baab597547Felipe Leme mClearUri.setOrder(order); 45508703c8bb19b518214bc352199bd46baab597547Felipe Leme mClearUriButton.setVisibility(View.VISIBLE); 45608703c8bb19b518214bc352199bd46baab597547Felipe Leme 45708703c8bb19b518214bc352199bd46baab597547Felipe Leme } 45808703c8bb19b518214bc352199bd46baab597547Felipe Leme 45908703c8bb19b518214bc352199bd46baab597547Felipe Leme private void clearUriPermissions() { 46020c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Leme final Context context = getActivity(); 46120c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Leme final String packageName = mAppEntry.info.packageName; 46208703c8bb19b518214bc352199bd46baab597547Felipe Leme // Synchronously revoke the permissions. 46320c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Leme final ActivityManager am = (ActivityManager) context.getSystemService( 46408703c8bb19b518214bc352199bd46baab597547Felipe Leme Context.ACTIVITY_SERVICE); 46520c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Leme am.clearGrantedUriPermissions(packageName); 46620c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Leme 46720c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Leme 46820c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Leme // Also update the Scoped Directory Access UI permissions 46920c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Leme final Uri providerUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) 47020c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Leme .authority(AUTHORITY).appendPath(TABLE_PERMISSIONS).appendPath("*") 47120c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Leme .build(); 47220c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Leme Log.v(TAG, "Asking " + providerUri + " to delete permissions for " + packageName); 47320c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Leme final int deleted = context.getContentResolver().delete(providerUri, null, new String[] { 47420c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Leme packageName 47520c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Leme }); 47620c5eb841b122fdbfeadf2df30321e7cd1e2f6c5Felipe Leme Log.d(TAG, "Deleted " + deleted + " entries for package " + packageName); 47708703c8bb19b518214bc352199bd46baab597547Felipe Leme 47808703c8bb19b518214bc352199bd46baab597547Felipe Leme // Update UI 47908703c8bb19b518214bc352199bd46baab597547Felipe Leme refreshGrantedUriPermissions(); 48008703c8bb19b518214bc352199bd46baab597547Felipe Leme } 48108703c8bb19b518214bc352199bd46baab597547Felipe Leme 48208703c8bb19b518214bc352199bd46baab597547Felipe Leme private void removeUriPermissionsFromUi() { 48308703c8bb19b518214bc352199bd46baab597547Felipe Leme // Remove all preferences but the clear button. 48408703c8bb19b518214bc352199bd46baab597547Felipe Leme int count = mUri.getPreferenceCount(); 48508703c8bb19b518214bc352199bd46baab597547Felipe Leme for (int i = count - 1; i >= 0; i--) { 48608703c8bb19b518214bc352199bd46baab597547Felipe Leme Preference pref = mUri.getPreference(i); 48708703c8bb19b518214bc352199bd46baab597547Felipe Leme if (pref != mClearUri) { 48808703c8bb19b518214bc352199bd46baab597547Felipe Leme mUri.removePreference(pref); 48908703c8bb19b518214bc352199bd46baab597547Felipe Leme } 49008703c8bb19b518214bc352199bd46baab597547Felipe Leme } 49108703c8bb19b518214bc352199bd46baab597547Felipe Leme } 49208703c8bb19b518214bc352199bd46baab597547Felipe Leme 493cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk @Override 494cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk protected AlertDialog createDialog(int id, int errorCode) { 495cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk switch (id) { 496cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk case DLG_CLEAR_DATA: 497cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk return new AlertDialog.Builder(getActivity()) 498cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk .setTitle(getActivity().getText(R.string.clear_data_dlg_title)) 499cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk .setMessage(getActivity().getText(R.string.clear_data_dlg_text)) 500cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() { 501cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk public void onClick(DialogInterface dialog, int which) { 502cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk // Clear user data here 503cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk initiateClearUserData(); 504cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 505cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk }) 506cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk .setNegativeButton(R.string.dlg_cancel, null) 507cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk .create(); 508cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk case DLG_CANNOT_CLEAR_DATA: 509cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk return new AlertDialog.Builder(getActivity()) 5106acc0cf3cdf3e47feb5a9c99adf4e732bfec9f2bFan Zhang .setTitle(getActivity().getText(R.string.clear_user_data_text)) 511cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk .setMessage(getActivity().getText(R.string.clear_failed_dlg_text)) 512cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk .setNeutralButton(R.string.dlg_ok, new DialogInterface.OnClickListener() { 513cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk public void onClick(DialogInterface dialog, int which) { 514ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mButtonsPref.setButton1Enabled(false); 515cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk //force to recompute changed value 516cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk setIntentAndFinish(false, false); 517cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 518cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk }) 519cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk .create(); 520cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 521cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk return null; 522cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 523cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 524cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk @Override 525cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk public void onPackageSizeChanged(String packageName) { 5263344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi } 5273344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi 5283344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi @Override 5293344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi public Loader<AppStorageStats> onCreateLoader(int id, Bundle args) { 5303344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi Context context = getContext(); 5313344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi return new FetchPackageStorageAsyncLoader( 5323344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi context, new StorageStatsSource(context), mInfo, UserHandle.of(mUserId)); 5333344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi } 5343344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi 5353344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi @Override 5363344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi public void onLoadFinished(Loader<AppStorageStats> loader, AppStorageStats result) { 5376a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi mSizeController.setResult(result); 5383344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi updateUiWithSize(result); 5393344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi } 5403344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi 5413344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi @Override 5423344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi public void onLoaderReset(Loader<AppStorageStats> loader) { 5433344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi } 5443344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi 5453344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi private void updateSize() { 5463344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi PackageManager packageManager = getPackageManager(); 5473344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi try { 5483344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi mInfo = packageManager.getApplicationInfo(mPackageName, 0); 5493344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi } catch (PackageManager.NameNotFoundException e) { 5503344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi Log.e(TAG, "Could not find package", e); 5513344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi } 5523344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi 5533344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi if (mInfo == null) { 5543344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi return; 5553344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi } 5563344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi 5573344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi getLoaderManager().restartLoader(1, Bundle.EMPTY, this); 5583344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi } 5593344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi 560ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang @VisibleForTesting 561ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang void updateUiWithSize(AppStorageStats result) { 5621359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi if (mCacheCleared) { 5631359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi mSizeController.setCacheCleared(true); 5641359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi } 565278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi if (mDataCleared) { 566278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi mSizeController.setDataCleared(true); 567278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi } 5681359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi 5696a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi mSizeController.updateUi(getContext()); 5706a256e77d624967470f60c68dab6d5447e8a24cbDaniel Nishi 5713344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi if (result == null) { 572ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mButtonsPref.setButton1Enabled(false).setButton2Enabled(false); 5733344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi } else { 5743344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi long cacheSize = result.getCacheBytes(); 5756f92b661a4c3d4a064d536fd466918b44fdacef1Daniel Nishi long dataSize = result.getDataBytes() - cacheSize; 5763344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi 577278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi if (dataSize <= 0 || !mCanClearData || mDataCleared) { 578ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mButtonsPref.setButton1Enabled(false); 5793344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi } else { 580ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mButtonsPref.setButton1Enabled(true) 581ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang .setButton1OnClickListener(v -> handleClearDataClick()); 5823344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi } 5831359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi if (cacheSize <= 0 || mCacheCleared) { 584ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mButtonsPref.setButton2Enabled(false); 5853344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi } else { 586ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mButtonsPref.setButton2Enabled(true) 587ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang .setButton2OnClickListener(v -> handleClearCacheClick()); 5883344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi } 5893344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi } 5903344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi if (mAppsControlDisallowedBySystem) { 591ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mButtonsPref.setButton1Enabled(false).setButton2Enabled(false); 592cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 593cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 594cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 595cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk private final Handler mHandler = new Handler() { 596cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk public void handleMessage(Message msg) { 597cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk if (getView() == null) { 598cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk return; 599cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 600cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk switch (msg.what) { 601cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk case MSG_CLEAR_USER_DATA: 602278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi mDataCleared = true; 603278bea730d52f65275f184a54a149d8258bba17fDaniel Nishi mCacheCleared = true; 604cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk processClearMsg(msg); 605cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk break; 606cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk case MSG_CLEAR_CACHE: 6071359d4fe0e1b445b7e8b36b1573ab03f8bcb3da1Daniel Nishi mCacheCleared = true; 608cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk // Refresh size info 6093344782bac06e871dd7da1c721cb299861f6b6ceDaniel Nishi updateSize(); 610cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk break; 611cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 612cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 613cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk }; 614cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 6158a963babe2e36b7a41f77b8d2598c97658196e58Chris Wren @Override 6166507613ebcd22e4691c2af92a5c161bd327db336Fan Zhang public int getMetricsCategory() { 6179d1bfd1e8de6e46137a9571507c03526880d6a46Chris Wren return MetricsEvent.APPLICATIONS_APP_STORAGE; 6188a963babe2e36b7a41f77b8d2598c97658196e58Chris Wren } 6198a963babe2e36b7a41f77b8d2598c97658196e58Chris Wren 620cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk class ClearCacheObserver extends IPackageDataObserver.Stub { 621cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk public void onRemoveCompleted(final String packageName, final boolean succeeded) { 622cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk final Message msg = mHandler.obtainMessage(MSG_CLEAR_CACHE); 623cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk msg.arg1 = succeeded ? OP_SUCCESSFUL : OP_FAILED; 624cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk mHandler.sendMessage(msg); 625cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 626cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 627cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk 628cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk class ClearUserDataObserver extends IPackageDataObserver.Stub { 629ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang public void onRemoveCompleted(final String packageName, final boolean succeeded) { 630ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang final Message msg = mHandler.obtainMessage(MSG_CLEAR_USER_DATA); 631ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang msg.arg1 = succeeded ? OP_SUCCESSFUL : OP_FAILED; 632ac06e1eeae81ace0563db11494420b7fb51cfe50Fan Zhang mHandler.sendMessage(msg); 633cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 634cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk } 635cd91128a2de5d111c59fe442c72b764d9a9acb3aJason Monk} 636