1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.deviceinfo.storage;
18 
19 import android.app.Dialog;
20 import android.app.settings.SettingsEnums;
21 import android.content.Context;
22 import android.content.pm.PackageManager.NameNotFoundException;
23 import android.os.Bundle;
24 import android.os.UserHandle;
25 import android.provider.MediaStore;
26 import android.util.Log;
27 
28 import androidx.appcompat.app.AlertDialog;
29 import androidx.fragment.app.Fragment;
30 
31 import com.android.settings.R;
32 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
33 import com.android.settingslib.utils.ThreadUtils;
34 
35 /**
36  * Dialog asks if users want to empty trash files.
37  * TODO(b/189388449): Shows "Deleting..." and disables Trash category while deleting trash files.
38  */
39 public class EmptyTrashFragment extends InstrumentedDialogFragment {
40     private static final String TAG = "EmptyTrashFragment";
41 
42     private static final String TAG_EMPTY_TRASH = "empty_trash";
43 
44     private final Fragment mParentFragment;
45     private final int mUserId;
46     private final long mTrashSize;
47     private final OnEmptyTrashCompleteListener mOnEmptyTrashCompleteListener;
48 
49     /** The listener to receive empty trash complete callback event. */
50     public interface OnEmptyTrashCompleteListener {
51         /** The empty trash complete callback. */
onEmptyTrashComplete()52         void onEmptyTrashComplete();
53     }
54 
EmptyTrashFragment(Fragment parent, int userId, long trashSize, OnEmptyTrashCompleteListener onEmptyTrashCompleteListener)55     public EmptyTrashFragment(Fragment parent, int userId, long trashSize,
56             OnEmptyTrashCompleteListener onEmptyTrashCompleteListener) {
57         super();
58 
59         mParentFragment = parent;
60         setTargetFragment(mParentFragment, 0 /* requestCode */);
61         mUserId = userId;
62         mTrashSize = trashSize;
63         mOnEmptyTrashCompleteListener = onEmptyTrashCompleteListener;
64     }
65 
66     /** Shows the empty trash dialog. */
show()67     public void show() {
68         show(mParentFragment.getFragmentManager(), TAG_EMPTY_TRASH);
69     }
70 
71     @Override
getMetricsCategory()72     public int getMetricsCategory() {
73         return SettingsEnums.DIALOG_EMPTY_TRASH;
74     }
75 
76     @Override
onCreateDialog(Bundle savedInstanceState)77     public Dialog onCreateDialog(Bundle savedInstanceState) {
78         final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
79         return builder.setTitle(R.string.storage_trash_dialog_title)
80                 .setMessage(getActivity().getString(R.string.storage_trash_dialog_ask_message,
81                         StorageUtils.getStorageSizeLabel(getActivity(), mTrashSize)))
82                 .setPositiveButton(R.string.storage_trash_dialog_confirm,
83                         (dialog, which) -> emptyTrashAsync())
84                 .setNegativeButton(android.R.string.cancel, null)
85                 .create();
86     }
87 
emptyTrashAsync()88     private void emptyTrashAsync() {
89         final Context context = getActivity();
90         final Context perUserContext;
91         try {
92             perUserContext = context.createPackageContextAsUser(
93                 context.getApplicationContext().getPackageName(),
94                 0 /* flags= */,
95                 UserHandle.of(mUserId));
96         } catch (NameNotFoundException e) {
97             Log.e(TAG, "Not able to get Context for user ID " + mUserId);
98             return;
99         }
100 
101         final Bundle trashQueryArgs = new Bundle();
102         trashQueryArgs.putInt(MediaStore.QUERY_ARG_MATCH_TRASHED, MediaStore.MATCH_ONLY);
103         ThreadUtils.postOnBackgroundThread(() -> {
104             perUserContext.getContentResolver().delete(
105                     MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL),
106                     trashQueryArgs);
107             if (mOnEmptyTrashCompleteListener == null) {
108                 return;
109             }
110             ThreadUtils.postOnMainThread(
111                     () -> mOnEmptyTrashCompleteListener.onEmptyTrashComplete());
112         });
113     }
114 }
115