Home | History | Annotate | Download | only in deletionhelper
      1 /*
      2  * Copyright (C) 2016 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.storagemanager.deletionhelper;
     18 
     19 import android.Manifest;
     20 import android.app.Activity;
     21 import android.content.pm.PackageManager;
     22 import android.os.Bundle;
     23 import android.support.v14.preference.PreferenceFragment;
     24 import android.text.format.Formatter;
     25 import android.view.Menu;
     26 import android.view.MenuInflater;
     27 import android.view.View;
     28 import android.widget.Button;
     29 import com.android.internal.logging.MetricsLogger;
     30 import com.android.internal.logging.MetricsProto.MetricsEvent;
     31 import com.android.settingslib.HelpUtils;
     32 import com.android.storagemanager.ButtonBarProvider;
     33 import com.android.storagemanager.R;
     34 
     35 import com.android.storagemanager.overlay.FeatureFactory;
     36 import com.android.storagemanager.overlay.DeletionHelperFeatureProvider;
     37 
     38 import java.util.ArrayList;
     39 import java.util.Collections;
     40 import java.util.HashSet;
     41 
     42 /**
     43  * Settings screen for the deletion helper, which manually removes data which is not recently used.
     44  */
     45 public class DeletionHelperSettings extends PreferenceFragment implements
     46         DeletionType.FreeableChangedListener,
     47         View.OnClickListener {
     48     private static final String APPS_KEY = "apps_group";
     49     private static final String KEY_DOWNLOADS_PREFERENCE = "delete_downloads";
     50     private static final String KEY_PHOTOS_VIDEOS_PREFERENCE = "delete_photos";
     51     private static final int DOWNLOADS_LOADER_ID = 1;
     52 
     53     private AppDeletionPreferenceGroup mApps;
     54     private AppDeletionType mAppBackend;
     55     private DownloadsDeletionPreferenceGroup mDownloadsPreference;
     56     private DownloadsDeletionType mDownloadsDeletion;
     57     private PhotosDeletionPreference mPhotoPreference;
     58     private DeletionType mPhotoVideoDeletion;
     59     private Button mCancel, mFree;
     60     private DeletionHelperFeatureProvider mProvider;
     61 
     62     public static DeletionHelperSettings newInstance() {
     63         return new DeletionHelperSettings();
     64     }
     65 
     66     @Override
     67     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
     68         addPreferencesFromResource(R.xml.deletion_helper_list);
     69         mApps = (AppDeletionPreferenceGroup) findPreference(APPS_KEY);
     70 
     71         HashSet<String> checkedApplications = null;
     72         if (savedInstanceState != null) {
     73             checkedApplications =
     74                     (HashSet<String>) savedInstanceState.getSerializable(
     75                             AppDeletionType.EXTRA_CHECKED_SET);
     76         }
     77         mAppBackend = new AppDeletionType(getActivity().getApplication(), checkedApplications);
     78         mAppBackend.registerView(mApps);
     79         mAppBackend.registerFreeableChangedListener(this);
     80         mApps.setDeletionType(mAppBackend);
     81 
     82         mPhotoPreference = (PhotosDeletionPreference) findPreference(KEY_PHOTOS_VIDEOS_PREFERENCE);
     83         mProvider = FeatureFactory.getFactory(getActivity()).getDeletionHelperFeatureProvider();
     84         if (mProvider != null) {
     85             mPhotoVideoDeletion = mProvider.createPhotoVideoDeletionType(getContext());
     86         }
     87     }
     88 
     89     @Override
     90     public void onActivityCreated(Bundle savedInstanceState) {
     91         super.onActivityCreated(savedInstanceState);
     92         initializeButtons();
     93         setHasOptionsMenu(true);
     94 
     95         Activity activity = getActivity();
     96         if (activity.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
     97                 != PackageManager.PERMISSION_GRANTED) {
     98             activity.requestPermissions(
     99                     new String[] {Manifest.permission.READ_EXTERNAL_STORAGE},
    100                     0);
    101         }
    102 
    103         if (mProvider == null || mPhotoVideoDeletion == null) {
    104             getPreferenceScreen().removePreference(mPhotoPreference);
    105             mPhotoPreference = null;
    106         } else {
    107             mPhotoPreference.registerFreeableChangedListener(this);
    108             mPhotoPreference.registerDeletionService(mPhotoVideoDeletion);
    109         }
    110 
    111         String[] uncheckedFiles = null;
    112         if (savedInstanceState != null) {
    113             uncheckedFiles = savedInstanceState.getStringArray(
    114                             DownloadsDeletionType.EXTRA_UNCHECKED_DOWNLOADS);
    115         }
    116         mDownloadsPreference =
    117                 (DownloadsDeletionPreferenceGroup) findPreference(KEY_DOWNLOADS_PREFERENCE);
    118         mDownloadsDeletion = new DownloadsDeletionType(getActivity(), uncheckedFiles);
    119         mDownloadsPreference.registerFreeableChangedListener(this);
    120         mDownloadsPreference.registerDeletionService(mDownloadsDeletion);
    121         updateFreeButtonText();
    122     }
    123 
    124     @Override
    125     public void onResume() {
    126         super.onResume();
    127         mAppBackend.onResume();
    128         mDownloadsDeletion.onResume();
    129 
    130         if (getActivity().checkSelfPermission(
    131                 Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
    132             getLoaderManager().initLoader(DOWNLOADS_LOADER_ID, new Bundle(), mDownloadsDeletion);
    133         }
    134 
    135         if (mPhotoVideoDeletion != null) {
    136             mPhotoVideoDeletion.onResume();
    137         }
    138     }
    139 
    140 
    141     @Override
    142     public void onPause() {
    143         super.onPause();
    144         mAppBackend.onPause();
    145         mDownloadsDeletion.onPause();
    146 
    147         if (mPhotoVideoDeletion != null) {
    148             mPhotoVideoDeletion.onPause();
    149         }
    150     }
    151 
    152     @Override
    153     public void onSaveInstanceState(Bundle outState) {
    154         super.onSaveInstanceState(outState);
    155         mAppBackend.onSaveInstanceStateBundle(outState);
    156         mDownloadsDeletion.onSaveInstanceStateBundle(outState);
    157     }
    158 
    159     @Override
    160     public void onFreeableChanged(int numItems, long bytesFreeable) {
    161         // bytesFreeable is the number of bytes freed by a single deletion type. If it is non-zero,
    162         // there is stuff to free and we can enable it. If it is zero, though, we still need to get
    163         // getTotalFreeableSpace to check all deletion types.
    164         mFree.setEnabled(bytesFreeable != 0 || getTotalFreeableSpace() != 0);
    165         updateFreeButtonText();
    166     }
    167 
    168     /**
    169      * Clears out the selected apps and data from the device and closes the fragment.
    170      */
    171     protected void clearData() {
    172         // This should be fine as long as there is only one extra deletion feature.
    173         // In the future, this should be done in an async queue in order to not
    174         // interfere with the simultaneous PackageDeletionTask.
    175         if (mPhotoPreference != null && mPhotoPreference.isChecked()) {
    176             mPhotoVideoDeletion.clearFreeableData(getActivity());
    177         }
    178         mDownloadsDeletion.clearFreeableData(getActivity());
    179         mAppBackend.clearFreeableData(getActivity());
    180     }
    181 
    182     @Override
    183     public void onClick(View v) {
    184         if (v.getId() == R.id.next_button) {
    185             ConfirmDeletionDialog dialog =
    186                     ConfirmDeletionDialog.newInstance(getTotalFreeableSpace());
    187             // The 0 is a placeholder for an optional result code.
    188             dialog.setTargetFragment(this, 0);
    189             dialog.show(getFragmentManager(), ConfirmDeletionDialog.TAG);
    190             MetricsLogger.action(getContext(), MetricsEvent.ACTION_DELETION_HELPER_CLEAR);
    191         } else {
    192             MetricsLogger.action(getContext(), MetricsEvent.ACTION_DELETION_HELPER_CANCEL);
    193             getActivity().finish();
    194         }
    195     }
    196 
    197     @Override
    198     public void onRequestPermissionsResult(int requestCode, String permissions[],
    199                                            int[] grantResults) {
    200         if (requestCode == 0) {
    201             if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    202                 mDownloadsDeletion.onResume();
    203                 getLoaderManager().initLoader(DOWNLOADS_LOADER_ID, new Bundle(),
    204                         mDownloadsDeletion);
    205             }
    206         }
    207     }
    208 
    209     @Override
    210     public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
    211         Activity activity = getActivity();
    212         String mHelpUri = getResources().getString(R.string.help_uri_deletion_helper);
    213         if (mHelpUri != null && activity != null) {
    214             HelpUtils.prepareHelpMenuItem(activity, menu, mHelpUri, getClass().getName());
    215         }
    216     }
    217 
    218     private void initializeButtons() {
    219         ButtonBarProvider activity = (ButtonBarProvider) getActivity();
    220         activity.getButtonBar().setVisibility(View.VISIBLE);
    221 
    222         mCancel = activity.getSkipButton();
    223         mCancel.setText(R.string.cancel);
    224         mCancel.setOnClickListener(this);
    225         mCancel.setVisibility(View.VISIBLE);
    226 
    227         mFree = activity.getNextButton();
    228         mFree.setText(R.string.storage_menu_free);
    229         mFree.setOnClickListener(this);
    230         mFree.setEnabled(false);
    231     }
    232 
    233     private void updateFreeButtonText() {
    234         mFree.setText(String.format(getActivity().getString(R.string.deletion_helper_free_button),
    235                 Formatter.formatFileSize(getActivity(), getTotalFreeableSpace())));
    236     }
    237 
    238     private long getTotalFreeableSpace() {
    239         long freeableSpace = 0;
    240         freeableSpace += mAppBackend.getTotalAppsFreeableSpace(false);
    241         if (mPhotoPreference != null) {
    242             freeableSpace += mPhotoPreference.getFreeableBytes();
    243         }
    244         freeableSpace += mDownloadsDeletion.getFreeableBytes();
    245         return freeableSpace;
    246     }
    247 }