1 /* |
|
2 * Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Message flow handler class |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 // INCLUDE FILES |
|
20 #include <coemain.h> |
|
21 |
|
22 #include "cimcvappmessageflowhandler.h" |
|
23 #include "mimcvenginemessagecontainer.h" |
|
24 #include "cimcvenginecontextobserver.h" |
|
25 #include "mimcvenginemessagesreadinterface.h" |
|
26 #include "imcvlogger.h" |
|
27 #include "cimcvappui.h" |
|
28 #include "cimcvengine.h" |
|
29 #include "mimcvenginechatinterface.h" |
|
30 |
|
31 |
|
32 // CONSTANTS |
|
33 const TInt KMilliToMicro = 1000; // multiplier for converting milliseconds to microseconds |
|
34 |
|
35 const TInt KTimeIntervalSlow = 2000; // slowest message speed (in milliseconds) |
|
36 const TInt KTimeIntervalFast = 200; // fastest message speed (in milliseconds) |
|
37 |
|
38 const TInt KTimeIntervalOpen = 0; // message fetching speed when opening the view |
|
39 const TInt KInitialMessages = 3; // fetch n messages at once when opening the view |
|
40 |
|
41 const TInt KSettingValueMin = 1; // minimum value for flow control setting |
|
42 const TInt KSettingValueMax = 3; // maximum value for flow control setting |
|
43 |
|
44 const TInt KIMFeatBackgroundGroupOpening = 0x00000008; |
|
45 |
|
46 // ============================ MEMBER FUNCTIONS =============================== |
|
47 |
|
48 // ----------------------------------------------------------------------------- |
|
49 // CIMCVAppMessageFlowHandler::CIMCVAppMessageFlowHandler |
|
50 // C++ default constructor can NOT contain any code, that |
|
51 // might leave. |
|
52 // ----------------------------------------------------------------------------- |
|
53 // |
|
54 CIMCVAppMessageFlowHandler::CIMCVAppMessageFlowHandler( MIMCVEngineMessageContainer& aMessageContainer, |
|
55 MIMCVEngineMessageReadInterface& aReadInterface,CIMCVEngine& aActiveEngine ) |
|
56 : CTimer( EPriorityStandard ), |
|
57 iMessages( aMessageContainer ), |
|
58 iReadInterface( aReadInterface ), |
|
59 iActiveEngine( aActiveEngine ), |
|
60 iFetchMessages( ETrue ) |
|
61 { |
|
62 CActiveScheduler::Add( this ); |
|
63 } |
|
64 |
|
65 |
|
66 // ----------------------------------------------------------------------------- |
|
67 // CCAMessageFlowHandler::NewL |
|
68 // Two-phased constructor. |
|
69 // ----------------------------------------------------------------------------- |
|
70 // |
|
71 CIMCVAppMessageFlowHandler* CIMCVAppMessageFlowHandler::NewL( |
|
72 MIMCVEngineMessageContainer& aMessageContainer, |
|
73 MIMCVEngineMessageReadInterface& aReadInterface, |
|
74 CIMCVEngine& aActiveEngine, |
|
75 TBool aScrollOver ) |
|
76 { |
|
77 CIMCVAppMessageFlowHandler* self = new( ELeave ) CIMCVAppMessageFlowHandler( |
|
78 aMessageContainer, |
|
79 aReadInterface , |
|
80 aActiveEngine ); |
|
81 |
|
82 CleanupStack::PushL( self ); |
|
83 self->ConstructL( aScrollOver ); |
|
84 CleanupStack::Pop( self ); |
|
85 |
|
86 return self; |
|
87 } |
|
88 // ----------------------------------------------------------------------------- |
|
89 // CIMCVAppMessageFlowHandler::ConstructL |
|
90 // Symbian 2nd phase constructor can leave. |
|
91 // ----------------------------------------------------------------------------- |
|
92 // |
|
93 void CIMCVAppMessageFlowHandler::ConstructL( TBool aScrollOver ) |
|
94 { |
|
95 // construct base class |
|
96 CTimer::ConstructL(); |
|
97 |
|
98 // for getting chat interface from CIMCVAPPAppUi |
|
99 iActiveEngine.ChatInterface().RegisterChatListObserver(this); |
|
100 |
|
101 // and observe changes |
|
102 iReadInterface.SetObserver( this ); |
|
103 iReadInterface.SetActive(ETrue); |
|
104 |
|
105 // fetch flow control value from settings |
|
106 UpdateTimeIntervalL(); |
|
107 |
|
108 if ( aScrollOver ) |
|
109 { |
|
110 iBgOpeningMode = EFalse; |
|
111 } |
|
112 else |
|
113 { |
|
114 iBgOpeningMode = 0 & KIMFeatBackgroundGroupOpening; |
|
115 } |
|
116 |
|
117 // start the timer if there are messages |
|
118 iInitialMsgCount = iReadInterface.MessageCount(); |
|
119 if( iInitialMsgCount + iReadInterface.UnreadCount() > 0 ) |
|
120 { |
|
121 // lock the buffer |
|
122 iReadInterface.Lock( ETrue ); |
|
123 |
|
124 // use faster timer when constructing |
|
125 iTimeInterval = KTimeIntervalOpen * KMilliToMicro; |
|
126 After( iTimeInterval ); |
|
127 } |
|
128 } |
|
129 |
|
130 |
|
131 // Destructor |
|
132 CIMCVAppMessageFlowHandler::~CIMCVAppMessageFlowHandler() |
|
133 { |
|
134 // for getting chat interface from CIMCVAPPAppUi |
|
135 iActiveEngine.ChatInterface().UnregisterChatListObserver(this); |
|
136 |
|
137 if ( !iChatDeleted ) |
|
138 { |
|
139 iReadInterface.SetActive(EFalse); |
|
140 iReadInterface.SetObserver( NULL ); |
|
141 iReadInterface.Lock( EFalse ); |
|
142 } |
|
143 Cancel(); |
|
144 } |
|
145 |
|
146 |
|
147 // ----------------------------------------------------------------------------- |
|
148 // CIMCVAppMessageFlowHandler::FetchMessages |
|
149 // (other items were commented in a header). |
|
150 // ----------------------------------------------------------------------------- |
|
151 // |
|
152 void CIMCVAppMessageFlowHandler::FetchMessages( TBool aFetch ) |
|
153 { |
|
154 TBool reallyInBg = |
|
155 CCoeEnv::Static()->RootWin().OrdinalPosition() == 0 ? EFalse : ETrue; |
|
156 |
|
157 if ( !reallyInBg && !aFetch ) |
|
158 { |
|
159 // Application is not really in background, this can happen |
|
160 // if key lock is activated while application is in foreground |
|
161 aFetch = ETrue; |
|
162 } |
|
163 |
|
164 iFetchMessages = aFetch; |
|
165 if( iFetchMessages && !iChatDeleted ) |
|
166 { |
|
167 // we're allowed to fetch messages again |
|
168 if( iReadInterface.UnreadCount() > 0 && !IsActive() ) |
|
169 { |
|
170 // there are some unread messages |
|
171 // => start the timer (if not active already) |
|
172 After( iTimeInterval ); |
|
173 } |
|
174 } |
|
175 |
|
176 else if( iMsgIndex < iInitialMsgCount ) |
|
177 { |
|
178 Cancel(); |
|
179 After( iTimeInterval ); |
|
180 return; |
|
181 } |
|
182 else |
|
183 { |
|
184 // we're not allowed to fetch new messages any more, so cancel the timer |
|
185 Cancel(); |
|
186 } |
|
187 } |
|
188 |
|
189 // ----------------------------------------------------------------------------- |
|
190 // CIMCVAppMessageFlowHandler::HandleMessageEvent |
|
191 // (other items were commented in a header). |
|
192 // ----------------------------------------------------------------------------- |
|
193 // |
|
194 void CIMCVAppMessageFlowHandler::HandleMessageEvent( TMessageEventType aEvent, |
|
195 TInt aIndex ) |
|
196 { |
|
197 IM_CV_LOGS(TXT("CIMCVAppMessageFlowHandler::HandleMessageEvent event %d, \ |
|
198 index %d"), aEvent, aIndex ); |
|
199 switch( aEvent ) |
|
200 { |
|
201 case ENewMessage: |
|
202 { |
|
203 if( !IsActive() && iFetchMessages ) |
|
204 { |
|
205 // if not active, start timer |
|
206 After( iTimeInterval ); |
|
207 } |
|
208 |
|
209 if ( IsOpening() && iBgOpeningMode ) |
|
210 { |
|
211 // New message during opening phase |
|
212 iNewMsgWhileOpening = ETrue; |
|
213 } |
|
214 |
|
215 // otherwise do nothing as timer fetches the messages |
|
216 break; |
|
217 } |
|
218 |
|
219 default: |
|
220 { |
|
221 break; |
|
222 } |
|
223 } |
|
224 } |
|
225 |
|
226 // ----------------------------------------------------------------------------- |
|
227 // CIMCVAppMessageFlowHandler::RunL |
|
228 // (other items were commented in a header). |
|
229 // ----------------------------------------------------------------------------- |
|
230 // |
|
231 void CIMCVAppMessageFlowHandler::RunL() |
|
232 { |
|
233 TBool messages( ETrue ); |
|
234 TBool opening = IsOpening(); |
|
235 |
|
236 // If we're opening the view, fetch KInitialMessages at a time, otherwise just one |
|
237 TInt count( opening ? KInitialMessages : 1 ); |
|
238 |
|
239 while( count-- > 0 && messages ) |
|
240 { |
|
241 if ( iBgOpeningMode && opening ) |
|
242 { |
|
243 // Opening the chat with background message fetching. |
|
244 // Perform steps in following order: |
|
245 // 1. Add possible new messages that are received during |
|
246 // the opening phase to the end of chat normally |
|
247 // 2. Insert unread messages to the beginning of chat |
|
248 |
|
249 if ( iNewMsgWhileOpening && iFetchMessages ) |
|
250 { |
|
251 // Add the new message now |
|
252 iMessages.AddMessageL( iReadInterface.ReadNextUnread() ); |
|
253 |
|
254 iNewMsgWhileOpening = EFalse; |
|
255 } |
|
256 else if ( iReadInterface.UnreadCount() > 0 && iFetchMessages ) |
|
257 { |
|
258 // Insert unread messages, insert in last-to-first order |
|
259 iAddedUnreadMsgs++; |
|
260 |
|
261 iMessages.InsertMessageL( |
|
262 iReadInterface.ReadUnreadFromIndex( |
|
263 iReadInterface.MessageCount() |
|
264 + iReadInterface.UnreadCount() |
|
265 - iAddedUnreadMsgs ) ); |
|
266 |
|
267 |
|
268 } |
|
269 |
|
270 else |
|
271 { |
|
272 // Check if the initial speed was active |
|
273 if ( opening ) |
|
274 { |
|
275 UpdateTimeIntervalL(); |
|
276 } |
|
277 messages = EFalse; |
|
278 iReadInterface.Lock( EFalse ); |
|
279 } |
|
280 } |
|
281 else |
|
282 { |
|
283 // Functionality in opening in releases 3.1 and earlier |
|
284 // and normal functionality when the chat is already fully opened |
|
285 // and new messages are received. |
|
286 |
|
287 // Add unread messages in first-to-last order |
|
288 if ( iReadInterface.UnreadCount() > 0 ) |
|
289 { |
|
290 // Add unread messages |
|
291 iMessages.AddMessageL( iReadInterface.ReadNextUnread() ); |
|
292 |
|
293 } |
|
294 else |
|
295 { |
|
296 // Check if the initial speed was active |
|
297 if ( opening ) |
|
298 { |
|
299 UpdateTimeIntervalL(); |
|
300 } |
|
301 messages = EFalse; |
|
302 iReadInterface.Lock( EFalse ); |
|
303 } |
|
304 } |
|
305 } |
|
306 |
|
307 // And restart timer if needed |
|
308 if ( messages ) |
|
309 { |
|
310 Cancel(); |
|
311 After( iTimeInterval ); |
|
312 } |
|
313 } |
|
314 |
|
315 // ----------------------------------------------------------------------------- |
|
316 // CIMCVAppMessageFlowHandler::RunError |
|
317 // (other items were commented in a header). |
|
318 // ----------------------------------------------------------------------------- |
|
319 // |
|
320 TInt CIMCVAppMessageFlowHandler::RunError( TInt aError ) |
|
321 { |
|
322 IM_CV_LOGS(TXT("CIMCVAppMessageFlowHandler::RunError (%d)"), aError ); |
|
323 |
|
324 // Something leaved in RunL |
|
325 if( aError == KErrNoMemory ) |
|
326 { |
|
327 // inform user about low memory |
|
328 CActiveScheduler::Current()->Error( aError ); |
|
329 } |
|
330 |
|
331 if( IsActive() ) |
|
332 { |
|
333 // stop processing messages |
|
334 Cancel(); |
|
335 } |
|
336 |
|
337 return KErrNone; |
|
338 } |
|
339 |
|
340 |
|
341 |
|
342 // ----------------------------------------------------------------------------- |
|
343 // CIMCVAppMessageFlowHandler::UpdateTimeIntervalL |
|
344 // (other items were commented in a header). |
|
345 // ----------------------------------------------------------------------------- |
|
346 // |
|
347 void CIMCVAppMessageFlowHandler::UpdateTimeIntervalL() |
|
348 { |
|
349 // codescanner warning can be ignored |
|
350 TInt flowSetting( 10 ); |
|
351 |
|
352 // flowSetting is from KSettingValueMin to KSettingValueMax |
|
353 TInt range( KSettingValueMax - KSettingValueMin ); |
|
354 TInt newRange( KTimeIntervalFast - KTimeIntervalSlow ); |
|
355 |
|
356 // convert it to a range from KTimeIntervalSlow to KTimeIntervalFast |
|
357 TInt flowSpeed( (flowSetting-KSettingValueMin)*newRange / range ); |
|
358 |
|
359 // update the end point |
|
360 flowSpeed += KTimeIntervalSlow; |
|
361 |
|
362 // validate the result |
|
363 if( flowSpeed > KTimeIntervalSlow ) |
|
364 { |
|
365 flowSpeed = KTimeIntervalSlow; |
|
366 } |
|
367 |
|
368 if( flowSpeed < KTimeIntervalFast ) |
|
369 { |
|
370 flowSpeed = KTimeIntervalFast; |
|
371 } |
|
372 |
|
373 // and convert from milliseconds to microseconds |
|
374 iTimeInterval = flowSpeed * KMilliToMicro; |
|
375 } |
|
376 |
|
377 // ----------------------------------------------------------------------------- |
|
378 // CIMCVAppMessageFlowHandler::IsOpening |
|
379 // (other items were commented in a header). |
|
380 // ----------------------------------------------------------------------------- |
|
381 // |
|
382 TBool CIMCVAppMessageFlowHandler::IsOpening() const |
|
383 { |
|
384 return iTimeInterval == |
|
385 TTimeIntervalMicroSeconds32( KTimeIntervalOpen * KMilliToMicro ); |
|
386 } |
|
387 |
|
388 // ----------------------------------------------------------------------------- |
|
389 // CIMCVAppMessageFlowHandler: HandleChatListEvent |
|
390 // ----------------------------------------------------------------------------- |
|
391 // |
|
392 void CIMCVAppMessageFlowHandler::HandleChatListEvent( TInt /*aServiceId*/, TChatListEventType aEvent, |
|
393 MIMCVEngineMessageReadInterface* /*aContainerInfo*/ |
|
394 ) |
|
395 { |
|
396 |
|
397 switch (aEvent) |
|
398 { |
|
399 case EChatItemAdded: |
|
400 { |
|
401 break; |
|
402 } |
|
403 |
|
404 case EChatItemDeleted: |
|
405 { |
|
406 iChatDeleted = ETrue; |
|
407 break; |
|
408 } |
|
409 |
|
410 default: |
|
411 break; |
|
412 } |
|
413 |
|
414 } |
|
415 |
|
416 // End of File |
|