1 /*
2 * Copyright 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.example.android.directboot.alarms;
18 
19 import android.content.Context;
20 import android.content.SharedPreferences;
21 import android.support.v4.os.BuildCompat;
22 import android.util.Log;
23 
24 import java.security.SecureRandom;
25 import java.util.HashSet;
26 import java.util.Map;
27 import java.util.Set;
28 
29 /**
30  * Class responsible for saving/retrieving alarms. This class uses SharedPreferences as storage.
31  */
32 public class AlarmStorage {
33 
34     private static final String TAG = AlarmStorage.class.getSimpleName();
35     private static final String ALARM_PREFERENCES_NAME = "alarm_preferences";
36     private static final SecureRandom SECURE_RANDOM = new SecureRandom();
37 
38     private SharedPreferences mSharedPreferences;
39 
AlarmStorage(Context context)40     public AlarmStorage(Context context) {
41         Context storageContext;
42         if (BuildCompat.isAtLeastN()) {
43             // All N devices have split storage areas, but we may need to
44             // move the existing preferences to the new device protected
45             // storage area, which is where the data lives from now on.
46             final Context deviceContext = context.createDeviceProtectedStorageContext();
47             if (!deviceContext.moveSharedPreferencesFrom(context,
48                     ALARM_PREFERENCES_NAME)) {
49                 Log.w(TAG, "Failed to migrate shared preferences.");
50             }
51             storageContext = deviceContext;
52         } else {
53             storageContext = context;
54         }
55         mSharedPreferences = storageContext
56                 .getSharedPreferences(ALARM_PREFERENCES_NAME, Context.MODE_PRIVATE);
57     }
58 
59     /**
60      * Stores an alarm in the SharedPreferences.
61      *
62      * @param month the integer represents a month
63      * @param date the integer represents a date
64      * @param hour the integer as 24-hour format the alarm goes off
65      * @param minute the integer of the minute the alarm goes off
66      * @return the saved {@link Alarm} instance
67      */
saveAlarm(int month, int date, int hour, int minute)68     public Alarm saveAlarm(int month, int date, int hour, int minute) {
69         Alarm alarm = new Alarm();
70         // Ignore the Id duplication if that happens
71         alarm.id = SECURE_RANDOM.nextInt();
72         alarm.month = month;
73         alarm.date = date;
74         alarm.hour = hour;
75         alarm.minute = minute;
76         SharedPreferences.Editor editor = mSharedPreferences.edit();
77         editor.putString(String.valueOf(alarm.id), alarm.toJson());
78         editor.apply();
79         return alarm;
80     }
81 
82     /**
83      * Retrieves the alarms stored in the SharedPreferences.
84      * This method takes linear time as the alarms count.
85      *
86      * @return a {@link Set} of alarms.
87      */
getAlarms()88     public Set<Alarm> getAlarms() {
89         Set<Alarm> alarms = new HashSet<>();
90         for (Map.Entry<String, ?> entry : mSharedPreferences.getAll().entrySet()) {
91             alarms.add(Alarm.fromJson(entry.getValue().toString()));
92         }
93         return alarms;
94     }
95 
96     /**
97      * Delete the alarm instance passed as an argument from the SharedPreferences.
98      * This method iterates through the alarms stored in the SharedPreferences, takes linear time
99      * as the alarms count.
100      *
101      * @param toBeDeleted the alarm instance to be deleted
102      */
deleteAlarm(Alarm toBeDeleted)103     public void deleteAlarm(Alarm toBeDeleted) {
104         for (Map.Entry<String, ?> entry : mSharedPreferences.getAll().entrySet()) {
105             Alarm alarm = Alarm.fromJson(entry.getValue().toString());
106             if (alarm.id == toBeDeleted.id) {
107                 SharedPreferences.Editor editor = mSharedPreferences.edit();
108                 editor.remove(String.valueOf(alarm.id));
109                 editor.apply();
110                 return;
111             }
112         }
113     }
114 }
115