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.sms;
18 
19 import android.content.res.Resources;
20 
21 import com.android.messaging.Factory;
22 import com.android.messaging.R;
23 import com.android.messaging.datamodel.SyncManager;
24 import com.android.messaging.util.BugleGservices;
25 import com.android.messaging.util.BugleGservicesKeys;
26 import com.android.messaging.util.LogUtil;
27 
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
30 
31 /**
32  * Class handling message cleanup when storage is low
33  */
34 public class SmsReleaseStorage {
35     /**
36      * Class representing a time duration specified by Gservices
37      */
38     public static class Duration {
39         // Time duration unit types
40         public static final int UNIT_WEEK = 'w';
41         public static final int UNIT_MONTH = 'm';
42         public static final int UNIT_YEAR = 'y';
43 
44         // Number of units
45         public final int mCount;
46         // Unit type: week, month or year
47         public final int mUnit;
48 
Duration(final int count, final int unit)49         public Duration(final int count, final int unit) {
50             mCount = count;
51             mUnit = unit;
52         }
53     }
54 
55     private static final String TAG = LogUtil.BUGLE_TAG;
56 
57     private static final Duration DEFAULT_DURATION = new Duration(1, Duration.UNIT_MONTH);
58 
59     private static final Pattern DURATION_PATTERN = Pattern.compile("([1-9]+\\d*)(w|m|y)");
60     /**
61      * Parse message retaining time duration specified by Gservices
62      *
63      * @return The parsed time duration from Gservices
64      */
parseMessageRetainingDuration()65     public static Duration parseMessageRetainingDuration() {
66         final String smsAutoDeleteMessageRetainingDuration =
67                 BugleGservices.get().getString(
68                         BugleGservicesKeys.SMS_STORAGE_PURGING_MESSAGE_RETAINING_DURATION,
69                         BugleGservicesKeys.SMS_STORAGE_PURGING_MESSAGE_RETAINING_DURATION_DEFAULT);
70         final Matcher matcher = DURATION_PATTERN.matcher(smsAutoDeleteMessageRetainingDuration);
71         try {
72             if (matcher.matches()) {
73                 return new Duration(
74                         Integer.parseInt(matcher.group(1)),
75                         matcher.group(2).charAt(0));
76             }
77         } catch (final NumberFormatException e) {
78             // Nothing to do
79         }
80         LogUtil.e(TAG, "SmsAutoDelete: invalid duration " +
81                 smsAutoDeleteMessageRetainingDuration);
82         return DEFAULT_DURATION;
83     }
84 
85     /**
86      * Get string representation of the time duration
87      *
88      * @param duration
89      * @return
90      */
getMessageRetainingDurationString(final Duration duration)91     public static String getMessageRetainingDurationString(final Duration duration) {
92         final Resources resources = Factory.get().getApplicationContext().getResources();
93         switch (duration.mUnit) {
94             case Duration.UNIT_WEEK:
95                 return resources.getQuantityString(
96                         R.plurals.week_count, duration.mCount, duration.mCount);
97             case Duration.UNIT_MONTH:
98                 return resources.getQuantityString(
99                         R.plurals.month_count, duration.mCount, duration.mCount);
100             case Duration.UNIT_YEAR:
101                 return resources.getQuantityString(
102                         R.plurals.year_count, duration.mCount, duration.mCount);
103         }
104         throw new IllegalArgumentException(
105                 "SmsAutoDelete: invalid duration unit " + duration.mUnit);
106     }
107 
108     // Time conversations
109     private static final long WEEK_IN_MILLIS = 7 * 24 * 3600 * 1000L;
110     private static final long MONTH_IN_MILLIS = 30 * 24 * 3600 * 1000L;
111     private static final long YEAR_IN_MILLIS = 365 * 24 * 3600 * 1000L;
112 
113     /**
114      * Convert time duration to time in milliseconds
115      *
116      * @param duration
117      * @return
118      */
durationToTimeInMillis(final Duration duration)119     public static long durationToTimeInMillis(final Duration duration) {
120         switch (duration.mUnit) {
121             case Duration.UNIT_WEEK:
122                 return duration.mCount * WEEK_IN_MILLIS;
123             case Duration.UNIT_MONTH:
124                 return duration.mCount * MONTH_IN_MILLIS;
125             case Duration.UNIT_YEAR:
126                 return duration.mCount * YEAR_IN_MILLIS;
127         }
128         return -1L;
129     }
130 
131     /**
132      * Delete message actions:
133      * 0: delete media messages
134      * 1: delete old messages
135      *
136      * @param actionIndex The index of the delete action to perform
137      * @param durationInMillis The time duration for retaining messages
138      */
deleteMessages(final int actionIndex, final long durationInMillis)139     public static void deleteMessages(final int actionIndex, final long durationInMillis) {
140         int deleted = 0;
141         switch (actionIndex) {
142             case 0: {
143                 // Delete media
144                 deleted = MmsUtils.deleteMediaMessages();
145                 break;
146             }
147             case 1: {
148                 // Delete old messages
149                 final long now = System.currentTimeMillis();
150                 final long cutOffTimestampInMillis = now - durationInMillis;
151                 // Delete messages from telephony provider
152                 deleted = MmsUtils.deleteMessagesOlderThan(cutOffTimestampInMillis);
153                 break;
154             }
155             default: {
156                 LogUtil.e(TAG, "SmsStorageStatusManager: invalid action " + actionIndex);
157                 break;
158             }
159         }
160 
161         if (deleted > 0) {
162             // Kick off a sync to update local db.
163             SyncManager.sync();
164         }
165     }
166 }
167