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.deskclock.data;
18
19import android.content.ContentResolver;
20import android.content.Context;
21import android.database.ContentObserver;
22import android.media.Ringtone;
23import android.media.RingtoneManager;
24import android.net.Uri;
25import android.os.Handler;
26import android.provider.Settings;
27import android.util.ArrayMap;
28
29import com.android.deskclock.LogUtils;
30import com.android.deskclock.R;
31import com.android.deskclock.provider.Alarm;
32
33import java.util.Map;
34
35/**
36 * All alarm data will eventually be accessed via this model.
37 */
38final class AlarmModel {
39
40    private final Context mContext;
41
42    /** The model from which settings are fetched. */
43    private final SettingsModel mSettingsModel;
44
45    /** The uri of the default ringtone to play for new alarms; mirrors last selection. */
46    private Uri mDefaultAlarmRingtoneUri;
47
48    /** Maps ringtone uri to ringtone title; looking up a title from scratch is expensive. */
49    private final Map<Uri, String> mRingtoneTitles = new ArrayMap<>(8);
50
51    AlarmModel(Context context, SettingsModel settingsModel) {
52        mContext = context;
53        mSettingsModel = settingsModel;
54
55        // Clear caches affected by system settings when system settings change.
56        final ContentResolver cr = mContext.getContentResolver();
57        final ContentObserver observer = new SystemAlarmAlertChangeObserver();
58        cr.registerContentObserver(Settings.System.DEFAULT_ALARM_ALERT_URI, false, observer);
59    }
60
61    Uri getDefaultAlarmRingtoneUri() {
62        if (mDefaultAlarmRingtoneUri == null) {
63            mDefaultAlarmRingtoneUri = mSettingsModel.getDefaultAlarmRingtoneUri();
64        }
65
66        return mDefaultAlarmRingtoneUri;
67    }
68
69    void setDefaultAlarmRingtoneUri(Uri uri) {
70        mSettingsModel.setDefaultAlarmRingtoneUri(uri);
71        mDefaultAlarmRingtoneUri = uri;
72    }
73
74    String getAlarmRingtoneTitle(Uri uri) {
75        // Special case: no ringtone has a title of "Silent".
76        if (Alarm.NO_RINGTONE_URI.equals(uri)) {
77            return mContext.getString(R.string.silent_ringtone_title);
78        }
79
80        // Check the cache.
81        String title = mRingtoneTitles.get(uri);
82
83        if (title == null) {
84            // This is slow because a media player is created during Ringtone object creation.
85            final Ringtone ringtone = RingtoneManager.getRingtone(mContext, uri);
86            if (ringtone == null) {
87                LogUtils.e("No ringtone for uri: %s", uri);
88                return mContext.getString(R.string.unknown_ringtone_title);
89            }
90
91            // Cache the title for later use.
92            title = ringtone.getTitle(mContext);
93            mRingtoneTitles.put(uri, title);
94        }
95        return title;
96    }
97
98    /**
99     * This receiver is notified when system settings change. Cached information built on
100     * those system settings must be cleared.
101     */
102    private final class SystemAlarmAlertChangeObserver extends ContentObserver {
103
104        private SystemAlarmAlertChangeObserver() {
105            super(new Handler());
106        }
107
108        @Override
109        public void onChange(boolean selfChange) {
110            super.onChange(selfChange);
111
112            LogUtils.i("Detected change to system default alarm ringtone; clearing caches");
113
114            mDefaultAlarmRingtoneUri = null;
115
116            // Titles such as "Default ringtone (Oxygen)" are wrong after default ringtone changes.
117            mRingtoneTitles.clear();
118        }
119    }
120}