1 /*
2  * Copyright (C) 2015 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.messaging.ui;
18 
19 import android.app.AlertDialog;
20 import android.app.Dialog;
21 import android.app.DialogFragment;
22 import android.app.Fragment;
23 import android.app.FragmentTransaction;
24 import android.content.Context;
25 import android.content.DialogInterface;
26 import android.content.res.Resources;
27 import android.os.Bundle;
28 import android.view.LayoutInflater;
29 import android.view.View;
30 import android.view.View.OnClickListener;
31 import android.view.ViewGroup;
32 import android.widget.ArrayAdapter;
33 import android.widget.ListView;
34 import android.widget.TextView;
35 
36 import com.android.messaging.R;
37 import com.android.messaging.datamodel.action.HandleLowStorageAction;
38 import com.android.messaging.sms.SmsReleaseStorage;
39 import com.android.messaging.sms.SmsReleaseStorage.Duration;
40 import com.android.messaging.sms.SmsStorageStatusManager;
41 import com.android.messaging.util.Assert;
42 import com.google.common.collect.Lists;
43 
44 import java.util.List;
45 
46 /**
47  * Dialog to show the sms storage low warning
48  */
49 public class SmsStorageLowWarningFragment extends Fragment {
SmsStorageLowWarningFragment()50     private SmsStorageLowWarningFragment() {
51     }
52 
newInstance()53     public static SmsStorageLowWarningFragment newInstance() {
54         return new SmsStorageLowWarningFragment();
55     }
56 
57     @Override
onCreate(final Bundle savedInstanceState)58     public void onCreate(final Bundle savedInstanceState) {
59         super.onCreate(savedInstanceState);
60         final FragmentTransaction ft = getFragmentManager().beginTransaction();
61         final ChooseActionDialogFragment dialog = ChooseActionDialogFragment.newInstance();
62         dialog.setTargetFragment(this, 0/*requestCode*/);
63         dialog.show(ft, null/*tag*/);
64     }
65 
66     /**
67      * Perform confirm action for a specific action
68      *
69      * @param actionIndex
70      */
confirm(final int actionIndex)71     private void confirm(final int actionIndex) {
72         final FragmentTransaction ft = getFragmentManager().beginTransaction();
73         final ConfirmationDialog dialog = ConfirmationDialog.newInstance(actionIndex);
74         dialog.setTargetFragment(this, 0/*requestCode*/);
75         dialog.show(ft, null/*tag*/);
76     }
77 
78     /**
79      * The dialog is cancelled at any step
80      */
cancel()81     private void cancel() {
82         getActivity().finish();
83     }
84 
85     /**
86      * The dialog to show for user to choose what delete actions to take when storage is low
87      */
88     private static class ChooseActionDialogFragment extends DialogFragment {
newInstance()89         public static ChooseActionDialogFragment newInstance() {
90             return new ChooseActionDialogFragment();
91         }
92 
93         @Override
onCreateDialog(final Bundle savedInstanceState)94         public Dialog onCreateDialog(final Bundle savedInstanceState) {
95             final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
96 
97             final LayoutInflater inflater = getActivity().getLayoutInflater();
98             final View dialogLayout = inflater.inflate(
99                     R.layout.sms_storage_low_warning_dialog, null);
100             final ListView actionListView = (ListView) dialogLayout.findViewById(
101                     R.id.free_storage_action_list);
102             final List<String> actions = loadFreeStorageActions(getActivity().getResources());
103             final ActionListAdapter listAdapter = new ActionListAdapter(getActivity(), actions);
104             actionListView.setAdapter(listAdapter);
105 
106             builder.setTitle(R.string.sms_storage_low_title)
107                     .setView(dialogLayout)
108                     .setNegativeButton(R.string.ignore, new DialogInterface.OnClickListener() {
109                         @Override
110                         public void onClick(DialogInterface dialog, int id) {
111                             dialog.cancel();
112                         }
113                     });
114 
115             final Dialog dialog = builder.create();
116             dialog.setCanceledOnTouchOutside(false);
117             return dialog;
118         }
119 
120         @Override
onCancel(final DialogInterface dialog)121         public void onCancel(final DialogInterface dialog) {
122             ((SmsStorageLowWarningFragment) getTargetFragment()).cancel();
123         }
124 
125         private class ActionListAdapter extends ArrayAdapter<String> {
ActionListAdapter(final Context context, final List<String> actions)126             public ActionListAdapter(final Context context, final List<String> actions) {
127                 super(context, R.layout.sms_free_storage_action_item_view, actions);
128             }
129 
130             @Override
getView(final int position, final View view, final ViewGroup parent)131             public View getView(final int position, final View view, final ViewGroup parent) {
132                 TextView actionItemView;
133                 if (view == null || !(view instanceof TextView)) {
134                     final LayoutInflater inflater = LayoutInflater.from(getContext());
135                     actionItemView = (TextView) inflater.inflate(
136                             R.layout.sms_free_storage_action_item_view, parent, false);
137                 } else {
138                     actionItemView = (TextView) view;
139                 }
140 
141                 final String action = getItem(position);
142                 actionItemView.setText(action);
143                 actionItemView.setOnClickListener(new OnClickListener() {
144                     @Override
145                     public void onClick(final View view) {
146                         dismiss();
147                         ((SmsStorageLowWarningFragment) getTargetFragment()).confirm(position);
148                     }
149                 });
150                 return actionItemView;
151             }
152         }
153     }
154 
155     private static final String KEY_ACTION_INDEX = "action_index";
156 
157     /**
158      * The dialog to confirm user's delete action
159      */
160     private static class ConfirmationDialog extends DialogFragment {
161         private Duration mDuration;
162         private String mDurationString;
163 
newInstance(final int actionIndex)164         public static ConfirmationDialog newInstance(final int actionIndex) {
165             final ConfirmationDialog dialog = new ConfirmationDialog();
166             final Bundle args = new Bundle();
167             args.putInt(KEY_ACTION_INDEX, actionIndex);
168             dialog.setArguments(args);
169             return dialog;
170         }
171 
172         @Override
onCancel(final DialogInterface dialog)173         public void onCancel(final DialogInterface dialog) {
174             ((SmsStorageLowWarningFragment) getTargetFragment()).cancel();
175         }
176 
177         @Override
onCreateDialog(final Bundle savedInstanceState)178         public Dialog onCreateDialog(final Bundle savedInstanceState) {
179             mDuration = SmsReleaseStorage.parseMessageRetainingDuration();
180             mDurationString = SmsReleaseStorage.getMessageRetainingDurationString(mDuration);
181 
182             final int actionIndex = getArguments().getInt(KEY_ACTION_INDEX);
183             if (actionIndex < 0 || actionIndex > 1) {
184                 return null;
185             }
186             final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
187             builder.setTitle(R.string.sms_storage_low_title)
188                     .setMessage(getConfirmDialogMessage(actionIndex))
189                     .setNegativeButton(android.R.string.cancel,
190                             new DialogInterface.OnClickListener() {
191                                 @Override
192                                 public void onClick(final DialogInterface dialog,
193                                         final int button) {
194                                     dismiss();
195                                     ((SmsStorageLowWarningFragment) getTargetFragment()).cancel();
196                                 }
197                     })
198                     .setPositiveButton(android.R.string.ok,
199                             new DialogInterface.OnClickListener() {
200                                 @Override
201                                 public void onClick(final DialogInterface dialog,
202                                         final int button) {
203                                     dismiss();
204                                     handleAction(actionIndex);
205                                     getActivity().finish();
206                                     SmsStorageStatusManager.cancelStorageLowNotification();
207                                 }
208                     });
209             return builder.create();
210         }
211 
handleAction(final int actionIndex)212         private void handleAction(final int actionIndex) {
213             final long durationInMillis =
214                     SmsReleaseStorage.durationToTimeInMillis(mDuration);
215             switch (actionIndex) {
216                 case 0:
217                     HandleLowStorageAction.handleDeleteMediaMessages(durationInMillis);
218                     break;
219 
220                 case 1:
221                     HandleLowStorageAction.handleDeleteOldMessages(durationInMillis);
222                     break;
223 
224                 default:
225                     Assert.fail("Unsupported action");
226                     break;
227             }
228         }
229 
230         /**
231          * Get the confirm dialog text for a specific delete action
232          * @param index The action index
233          * @return
234          */
getConfirmDialogMessage(final int index)235         private String getConfirmDialogMessage(final int index) {
236             switch (index) {
237                 case 0:
238                     return getString(R.string.delete_all_media_confirmation, mDurationString);
239                 case 1:
240                     return getString(R.string.delete_oldest_messages_confirmation, mDurationString);
241                 case 2:
242                     return getString(R.string.auto_delete_oldest_messages_confirmation,
243                             mDurationString);
244             }
245             throw new IllegalArgumentException(
246                     "SmsStorageLowWarningFragment: invalid action index " + index);
247         }
248     }
249 
250     /**
251      * Load the text of delete message actions
252      *
253      * @param resources
254      * @return
255      */
loadFreeStorageActions(final Resources resources)256     private static List<String> loadFreeStorageActions(final Resources resources) {
257         final Duration duration = SmsReleaseStorage.parseMessageRetainingDuration();
258         final String durationString = SmsReleaseStorage.getMessageRetainingDurationString(duration);
259         final List<String> actions = Lists.newArrayList();
260         actions.add(resources.getString(R.string.delete_all_media));
261         actions.add(resources.getString(R.string.delete_oldest_messages, durationString));
262 
263         // TODO: Auto-purging is disabled for Bugle V1.
264         // actions.add(resources.getString(R.string.auto_delete_oldest_messages, durationString));
265         return actions;
266     }
267 }
268