Add WatchfaceComplication.dll and fix some bugs (#703)
[platform/core/csapi/tizenfx.git] / src / Tizen.Applications.WatchfaceComplication / Tizen.Applications / EditablesContainer.cs
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
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 using System;
18 using System.Collections.Generic;
19
20 namespace Tizen.Applications.WatchfaceComplication
21 {
22     /// <summary>
23     /// Represents the EditablesContainer class for the watch application.
24     /// </summary>
25     /// <since_tizen> 6 </since_tizen>
26     public abstract class EditablesContainer : IDisposable
27     {
28         internal IList<DesignElement> _deList = new List<DesignElement>();
29         internal IList<Complication> _compList = new List<Complication>();
30         internal IntPtr _container = IntPtr.Zero;
31         private Interop.WatchfaceComplication.EditableUpdateRequestedCallback _editableUpdatedCallback;
32         private readonly Interop.WatchfaceComplication.EditReadyCallback _editReadyCallback;
33         private bool _disposed = false;
34         private static string _logTag = "WatchfaceComplication";
35
36         /// <summary>
37         /// Initializes the EditablesContainer class.
38         /// </summary>
39         /// <exception cref="ArgumentException">Thrown when some parameter are invalid.</exception>
40         /// <exception cref="InvalidOperationException">Thrown when the method failed due to invalid operation.</exception>
41         /// <exception cref="NotSupportedException">Thrown when the watchface complication is not supported.</exception>
42         /// <since_tizen> 6 </since_tizen>
43         protected EditablesContainer()
44         {
45             _editReadyCallback = new Interop.WatchfaceComplication.EditReadyCallback(EditReady);
46             ComplicationError err = Interop.WatchfaceComplication.AddEditReadyCallback(_editReadyCallback, IntPtr.Zero);
47             if (err != ComplicationError.None)
48                 ErrorFactory.ThrowException(err, "Fail to add edit ready callback");
49             Log.Debug(_logTag, "Edit container ready");
50         }
51
52         /// <summary>
53         /// Destructor of the EditablesContainer class.
54         /// </summary>
55         ~EditablesContainer()
56         {
57             Dispose(false);
58         }
59
60         /// <summary>
61         /// Adds the DesignElement to edit list.
62         /// </summary>
63         /// <param name="de">The DesignElement object.</param>
64         /// <param name="editableId">The editable id.</param>
65         /// <exception cref="ArgumentException">Thrown when the invalid parameter is passed.</exception>
66         /// <exception cref="InvalidOperationException">Thrown when the method failed due to invalid operation.</exception>
67         /// <since_tizen> 6 </since_tizen>
68         public void Add(DesignElement de, int editableId)
69         {
70             if (de == null)
71                 ErrorFactory.ThrowException(ComplicationError.InvalidParam);
72             if (IsExist(editableId))
73                 ErrorFactory.ThrowException(ComplicationError.ExistID);
74
75             IEditable e = de;
76             e.EditableId = editableId;
77             _deList.Add(de);
78         }
79
80         /// <summary>
81         /// Adds the Complication to edit list.
82         /// </summary>
83         /// <param name="comp">The Complication object.</param>
84         /// <param name="editableId">The editable id.</param>
85         /// <exception cref="ArgumentException">Thrown when the invalid parameter is passed.</exception>
86         /// <exception cref="InvalidOperationException">Thrown when the method failed due to invalid operation.</exception>
87         /// <since_tizen> 6 </since_tizen>
88         public void Add(Complication comp, int editableId)
89         {
90             if (comp == null)
91                 ErrorFactory.ThrowException(ComplicationError.InvalidParam);
92             if (IsExist(editableId))
93                 ErrorFactory.ThrowException(ComplicationError.ExistID);
94
95             IEditable e = comp;
96             e.EditableId = editableId;
97             _compList.Add(comp);
98         }
99
100         /// <summary>
101         /// Removes the editable from edit list.
102         /// </summary>
103         /// <param name="editableId">The editable id.</param>
104         /// <exception cref="ArgumentException">Thrown when the invalid parameter is passed.</exception>
105         /// <example>
106         /// <code>
107         /// if (myContainer.IsExist(_colorEditId)
108         ///     myContainer.Remove(_colorEditId);
109         /// </code>
110         /// </example>
111         /// <since_tizen> 6 </since_tizen>
112         public void Remove(int editableId)
113         {
114             foreach (DesignElement de in _deList)
115             {
116                 if (((IEditable)de).EditableId == editableId)
117                 {
118                     _deList.Remove(de);
119                     return;
120                 }
121             }
122
123             foreach (Complication comp in _compList)
124             {
125                 if (((IEditable)comp).EditableId == editableId)
126                 {
127                     _compList.Remove(comp);
128                     return;
129                 }
130             }
131
132             ErrorFactory.ThrowException(ComplicationError.InvalidParam, "invalid editable ID");
133         }
134
135         internal IEditable GetEditable(int editableId)
136         {
137             foreach (IEditable ed in _deList)
138             {
139                 if (ed.EditableId == editableId)
140                     return ed;
141             }
142
143             foreach (IEditable ed in _compList)
144             {
145                 if (ed.EditableId == editableId)
146                     return ed;
147             }
148
149             return null;
150         }
151
152         internal DesignElement GetDesignElement(int editableId)
153         {
154             foreach (DesignElement de in _deList)
155             {
156                 IEditable ed = de;
157                 if (ed.EditableId == editableId)
158                     return de;
159             }
160
161             return null;
162         }
163
164         /// <summary>
165         /// Checks the editable with editableId is already exists in edit list.
166         /// </summary>
167         /// <param name="editableId">The target editable Id.</param>
168         /// <returns>true if the editable is already exists in edit list, otherwise false</returns>
169         /// <since_tizen> 6 </since_tizen>
170         public bool IsExist(int editableId)
171         {
172             return (GetEditable(editableId) != null);
173         }
174
175         private void EditReady(IntPtr container, string editorAppid, IntPtr userData)
176         {
177             OnEditReady(editorAppid);
178         }
179
180
181         private void EditableUpdatedCallback(IntPtr handle, int selectedIdx,
182             int state, IntPtr userData)
183         {
184             int editableId;
185             ComplicationError err = Interop.WatchfaceComplication.GetEditableId(handle, out editableId);
186             if (err != ComplicationError.None)
187                 ErrorFactory.ThrowException(err, "fail to get current index");
188
189             int currentIdx;
190             err = Interop.WatchfaceComplication.GetCurrentIdx(handle, out currentIdx);
191             if (err != ComplicationError.None)
192                 ErrorFactory.ThrowException(err, "fail to get current index");
193
194             DesignElement de = GetDesignElement(editableId);
195             if (de != null)
196             {
197                 de.SetCurrentDataIndex(currentIdx);
198                 de.NotifyUpdate(currentIdx, (State)state);
199             }
200         }
201
202         /// <summary>
203         /// Requests edit to editor application.
204         /// </summary>
205         /// <privilege>http://tizen.org/privilege/datasharing</privilege>
206         /// <exception cref="InvalidOperationException">Thrown when the method failed due to invalid operation.</exception>
207         /// <exception cref="NotSupportedException">Thrown when the watchface complication is not supported.</exception>
208         /// <exception cref="UnauthorizedAccessException">Thrown when the application does not have privilege to access this method.</exception>
209         /// <example>
210         /// <code>
211         /// public class MyContainer : EditablesContainer {
212         ///     public MyContainer() : base()
213         ///     {
214         ///     }
215         ///     protected override void OnEditReady(string editorId)
216         ///     {
217         ///         this.RequestEdit();
218         ///     }
219         /// }
220         /// </code>
221         /// </example>
222         /// <since_tizen> 6 </since_tizen>
223         public void RequestEdit()
224         {
225             Log.Debug(_logTag, "request edit");
226             ComplicationError ret;
227
228             Interop.WatchfaceComplication.GetEditableContainer(out _container);
229             if (_container == IntPtr.Zero)
230             {
231                 ErrorFactory.ThrowException(ComplicationError.EditNotReady, "Editor not ready");
232             }
233
234             if (_editableUpdatedCallback == null)
235                 _editableUpdatedCallback = new Interop.WatchfaceComplication.EditableUpdateRequestedCallback(EditableUpdatedCallback);
236
237             foreach (Complication comp in _compList)
238             {
239                 IEditable e = comp;
240                 IntPtr hi = IntPtr.Zero;
241                 if (e.Highlight != null && e.Highlight.Raw != IntPtr.Zero)
242                     hi = e.Highlight.Raw;
243                 Interop.WatchfaceComplication.AddComplication(_container, e.EditableId, comp._handle, hi);
244             }
245
246             foreach (DesignElement de in _deList)
247             {
248                 IEditable e = de;
249                 IntPtr candidates;
250                 Interop.WatchfaceComplication.CreateCandidatesList(out candidates);
251                 foreach (Bundle b in de.Candidates)
252                 {
253                     Interop.WatchfaceComplication.AddCandidatesListItem(candidates, b.SafeBundleHandle);
254                 }
255
256                 IntPtr hi = IntPtr.Zero;
257                 if (e.Highlight != null && e.Highlight.Raw != IntPtr.Zero)
258                     hi = e.Highlight.Raw;
259                 Interop.WatchfaceComplication.AddDesignElement(_container, e.EditableId, e.GetCurrentDataIndex(), candidates, hi, e.Name);
260                 Log.Debug(_logTag, "Add design element done :" + e.Name);
261             }
262
263             ret = Interop.WatchfaceComplication.RequestEdit(_container, _editableUpdatedCallback, IntPtr.Zero);
264             if (ret != ComplicationError.None)
265             {
266                 ErrorFactory.ThrowException(ret, "Request edit fail");
267             }
268         }
269
270         /// <summary>
271         /// Overrides this method if you want to handle the behavior when the editor is ready to edit.
272         /// </summary>
273         /// <param name="editorId">The appid of ready to edit editor.</param>
274         /// <since_tizen> 6 </since_tizen>
275         protected abstract void OnEditReady(string editorId);
276
277         /// <summary>
278         /// Loads the editable's current data.
279         /// </summary>
280         /// <returns>The editable's latest data that selected by editor.</returns>
281         /// <exception cref="ArgumentException">Thrown when some parameter are invalid.</exception>
282         /// <exception cref="InvalidOperationException">Thrown when the method failed due to invalid operation.</exception>
283         /// <exception cref="NotSupportedException">Thrown when the watchface complication is not supported.</exception>
284         /// <remarks>
285         /// This API loads editable's last current data which is updated by editor application.
286         /// </remarks>
287         /// <param name="editableId">The id of the editable.</param>
288         /// <example>
289         /// <code>
290         /// internal void InitEditables()
291         /// {
292         ///     _container = new MyContainer();
293         ///     Bundle curData = EditablesContainer.LoadCurrentData(_colorEditId);
294         ///     List&lt;Bundle&gt; candidatesList = new List&lt;Bundle&gt;();
295         ///     int curIdx = 0;
296         ///     int i = 0;
297         ///     foreach (string str in _colorArr)
298         ///     {
299         ///         Bundle data = new Bundle();
300         ///         data.AddItem(_colorKey, str);
301         ///         candidatesList.Add(data);
302         ///         if (curData != null &amp;&amp; curData.GetItem(_colorKey) != null
303         ///             &amp;&amp; curData.GetItem(_colorKey).Equals(str))
304         ///         {
305         ///             curIdx = i;
306         ///         }
307         ///         i++;
308         ///    }
309         ///    ColorDesign colorEdit = new ColorDesign(candidatesList, curIdx, "COLOR", _complicationBtn);
310         ///    colorEdit.Highlight = new Highlight(ShapeType.Circle, 0, 40, 10, 10);
311         ///    _container.Add(colorEdit, _colorEditId);
312         /// }
313         /// </code>
314         /// </example>
315         /// <since_tizen> 6 </since_tizen>
316         public static Bundle LoadCurrentData(int editableId)
317         {
318             SafeBundleHandle handle;
319             ComplicationError err = Interop.WatchfaceComplication.LoadCurrentData(editableId, out handle);
320             if (err == ComplicationError.None)
321                 return new Bundle(handle);
322
323             return null;
324         }
325
326         /// <summary>
327         /// Releases the unmanaged resources used by the EditablesContainer class specifying whether to perform a normal dispose operation.
328         /// </summary>
329         /// <param name="disposing">true for a normal dispose operation; false to finalize the handle.</param>
330         /// <since_tizen> 3 </since_tizen>
331         protected virtual void Dispose(bool disposing)
332         {
333             if (!_disposed)
334             {
335                 Interop.WatchfaceComplication.RemoveEditReadyCallback(_editReadyCallback);
336                 _disposed = true;
337             }
338         }
339
340         /// <summary>
341         /// Releases all resources used by the EditablesContainer class.
342         /// </summary>
343         /// <since_tizen> 3 </since_tizen>
344         public void Dispose()
345         {
346             Dispose(true);
347             GC.SuppressFinalize(this);
348         }
349     };
350 }