1 /*
2  * Copyright (C) 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.android.voicemail.impl;
18 
19 import android.content.ContentResolver;
20 import android.content.ContentValues;
21 import android.content.Context;
22 import android.net.Uri;
23 import android.provider.VoicemailContract;
24 import android.provider.VoicemailContract.Status;
25 import android.support.annotation.Nullable;
26 import android.telecom.PhoneAccountHandle;
27 import com.android.dialer.strictmode.StrictModeUtils;
28 
29 public class VoicemailStatus {
30 
31   private static final String TAG = "VvmStatus";
32 
33   public static class Editor {
34 
35     private final Context context;
36     @Nullable private final PhoneAccountHandle phoneAccountHandle;
37 
38     private ContentValues values = new ContentValues();
39 
Editor(Context context, PhoneAccountHandle phoneAccountHandle)40     private Editor(Context context, PhoneAccountHandle phoneAccountHandle) {
41       this.context = context;
42       this.phoneAccountHandle = phoneAccountHandle;
43       if (this.phoneAccountHandle == null) {
44         VvmLog.w(
45             TAG,
46             "VoicemailStatus.Editor created with null phone account, status will"
47                 + " not be written");
48       }
49     }
50 
51     @Nullable
getPhoneAccountHandle()52     public PhoneAccountHandle getPhoneAccountHandle() {
53       return phoneAccountHandle;
54     }
55 
setType(String type)56     public Editor setType(String type) {
57       values.put(Status.SOURCE_TYPE, type);
58       return this;
59     }
60 
setConfigurationState(int configurationState)61     public Editor setConfigurationState(int configurationState) {
62       values.put(Status.CONFIGURATION_STATE, configurationState);
63       return this;
64     }
65 
setDataChannelState(int dataChannelState)66     public Editor setDataChannelState(int dataChannelState) {
67       values.put(Status.DATA_CHANNEL_STATE, dataChannelState);
68       return this;
69     }
70 
setNotificationChannelState(int notificationChannelState)71     public Editor setNotificationChannelState(int notificationChannelState) {
72       values.put(Status.NOTIFICATION_CHANNEL_STATE, notificationChannelState);
73       return this;
74     }
75 
setQuota(int occupied, int total)76     public Editor setQuota(int occupied, int total) {
77       if (occupied == VoicemailContract.Status.QUOTA_UNAVAILABLE
78           && total == VoicemailContract.Status.QUOTA_UNAVAILABLE) {
79         return this;
80       }
81 
82       values.put(Status.QUOTA_OCCUPIED, occupied);
83       values.put(Status.QUOTA_TOTAL, total);
84       return this;
85     }
86 
87     /**
88      * Apply the changes to the {@link VoicemailStatus} {@link #Editor}.
89      *
90      * @return {@code true} if the changes were successfully applied, {@code false} otherwise.
91      */
apply()92     public boolean apply() {
93       if (phoneAccountHandle == null) {
94         return false;
95       }
96       values.put(
97           Status.PHONE_ACCOUNT_COMPONENT_NAME,
98           phoneAccountHandle.getComponentName().flattenToString());
99       values.put(Status.PHONE_ACCOUNT_ID, phoneAccountHandle.getId());
100       ContentResolver contentResolver = context.getContentResolver();
101       Uri statusUri = VoicemailContract.Status.buildSourceUri(context.getPackageName());
102       try {
103         StrictModeUtils.bypass(() -> contentResolver.insert(statusUri, values));
104       } catch (IllegalArgumentException iae) {
105         VvmLog.e(TAG, "apply :: failed to insert content resolver ", iae);
106         values.clear();
107         return false;
108       }
109       values.clear();
110       return true;
111     }
112 
getValues()113     public ContentValues getValues() {
114       return values;
115     }
116   }
117 
118   /**
119    * A voicemail status editor that the decision of whether to actually write to the database can be
120    * deferred. This object will be passed around as a usual {@link Editor}, but {@link #apply()}
121    * doesn't do anything. If later the creator of this object decides any status changes written to
122    * it should be committed, {@link #deferredApply()} should be called.
123    */
124   public static class DeferredEditor extends Editor {
125 
DeferredEditor(Context context, PhoneAccountHandle phoneAccountHandle)126     private DeferredEditor(Context context, PhoneAccountHandle phoneAccountHandle) {
127       super(context, phoneAccountHandle);
128     }
129 
130     @Override
apply()131     public boolean apply() {
132       // Do nothing
133       return true;
134     }
135 
deferredApply()136     public void deferredApply() {
137       super.apply();
138     }
139   }
140 
edit(Context context, PhoneAccountHandle phoneAccountHandle)141   public static Editor edit(Context context, PhoneAccountHandle phoneAccountHandle) {
142     return new Editor(context, phoneAccountHandle);
143   }
144 
145   /**
146    * Reset the status to the "disabled" state, which the UI should not show anything for this
147    * phoneAccountHandle.
148    */
disable(Context context, PhoneAccountHandle phoneAccountHandle)149   public static void disable(Context context, PhoneAccountHandle phoneAccountHandle) {
150     edit(context, phoneAccountHandle)
151         .setConfigurationState(Status.CONFIGURATION_STATE_NOT_CONFIGURED)
152         .setDataChannelState(Status.DATA_CHANNEL_STATE_NO_CONNECTION)
153         .setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_NO_CONNECTION)
154         .apply();
155   }
156 
deferredEdit( Context context, PhoneAccountHandle phoneAccountHandle)157   public static DeferredEditor deferredEdit(
158       Context context, PhoneAccountHandle phoneAccountHandle) {
159     return new DeferredEditor(context, phoneAccountHandle);
160   }
161 }
162