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
17package com.android.messaging.ui;
18
19import android.app.AlertDialog;
20import android.app.Dialog;
21import android.app.DialogFragment;
22import android.app.Fragment;
23import android.app.FragmentTransaction;
24import android.content.Context;
25import android.content.DialogInterface;
26import android.content.res.Resources;
27import android.os.Bundle;
28import android.view.LayoutInflater;
29import android.view.View;
30import android.view.View.OnClickListener;
31import android.view.ViewGroup;
32import android.widget.ArrayAdapter;
33import android.widget.ListView;
34import android.widget.TextView;
35
36import com.android.messaging.R;
37import com.android.messaging.datamodel.action.HandleLowStorageAction;
38import com.android.messaging.sms.SmsReleaseStorage;
39import com.android.messaging.sms.SmsReleaseStorage.Duration;
40import com.android.messaging.sms.SmsStorageStatusManager;
41import com.android.messaging.util.Assert;
42import com.google.common.collect.Lists;
43
44import java.util.List;
45
46/**
47 * Dialog to show the sms storage low warning
48 */
49public class SmsStorageLowWarningFragment extends Fragment {
50    private SmsStorageLowWarningFragment() {
51    }
52
53    public static SmsStorageLowWarningFragment newInstance() {
54        return new SmsStorageLowWarningFragment();
55    }
56
57    @Override
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     */
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     */
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 {
89        public static ChooseActionDialogFragment newInstance() {
90            return new ChooseActionDialogFragment();
91        }
92
93        @Override
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
121        public void onCancel(final DialogInterface dialog) {
122            ((SmsStorageLowWarningFragment) getTargetFragment()).cancel();
123        }
124
125        private class ActionListAdapter extends ArrayAdapter<String> {
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
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
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
173        public void onCancel(final DialogInterface dialog) {
174            ((SmsStorageLowWarningFragment) getTargetFragment()).cancel();
175        }
176
177        @Override
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
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         */
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     */
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