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