|
1 /* |
|
2 * Copyright (c) 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: Base class for position request classes |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 // INCLUDE FILES |
|
20 #include "cpositionerbase.h" |
|
21 #include "s60commonutils.h" |
|
22 #include "logger.h" |
|
23 |
|
24 using namespace java::location; |
|
25 |
|
26 // UNNAMED LOCAL NAMESPACE |
|
27 namespace |
|
28 { |
|
29 // Default size of the position info buffer if NMEA statements are supported |
|
30 // In fact, this is four times the standard buffer size |
|
31 const TInt KLocPositionGenericInfoNMEABufferSize = 0x1000; // Dec 4096 |
|
32 |
|
33 // Default maximum number of fields if NMEA statements are supported |
|
34 // In fact, this is four times the default field count |
|
35 const TInt KLocPositionGenericInfoNMEAFieldCount = 0x0080; // Dec 128 |
|
36 |
|
37 // Default buffer size increase. This is based on to BT GPS PSY standard |
|
38 // buffer which is the size of 5K. Usually 1K increase should be enough |
|
39 // since it is the standard size of HPositionGenericInfo when constructed |
|
40 const TInt KLocBufferSizeIncrease = 0x0400; // 1024 |
|
41 |
|
42 // Default increase for accepted fields in position info buffer. This is based |
|
43 // on to MLFW default field count which is 32. The increse is synchronized |
|
44 // with the buffer size increase as these values are the same default values |
|
45 // which are used when HPositionGenericInfo is generated without parameters |
|
46 const TInt KLocFieldCountIncrease = 0x0020; // 32 |
|
47 |
|
48 const TInt KNumFields = 17; |
|
49 const TUint16 positionField[KNumFields] = |
|
50 { EPositionFieldStreetExtension, EPositionFieldStreet, |
|
51 EPositionFieldPostalCode, EPositionFieldCity, EPositionFieldCounty, |
|
52 EPositionFieldState, EPositionFieldCountry, EPositionFieldCountryCode, |
|
53 EPositionFieldDistrict, EPositionFieldBuildingName, |
|
54 EPositionFieldBuildingFloor, EPositionFieldBuildingRoom, |
|
55 EPositionFieldBuildingZone, EPositionFieldCrossing1, |
|
56 EPositionFieldCrossing2, EPositionFieldMediaLinks, |
|
57 EPositionFieldBuildingTelephone |
|
58 }; |
|
59 } |
|
60 |
|
61 // ============================ MEMBER FUNCTIONS =============================== |
|
62 |
|
63 // ----------------------------------------------------------------------------- |
|
64 // CPositionerBase::CPositionerBase |
|
65 // C++ default constructor can NOT contain any code, that |
|
66 // might leave. |
|
67 // ----------------------------------------------------------------------------- |
|
68 // |
|
69 CPositionerBase::CPositionerBase(LocationFunctionServer* aFunctionSource) : |
|
70 CActive(EPriorityNormal), mFunctionServer(aFunctionSource), iCapabilities( |
|
71 TPositionModuleInfo::ECapabilityNone) |
|
72 { |
|
73 CActiveScheduler::Add(this); |
|
74 } |
|
75 |
|
76 // ----------------------------------------------------------------------------- |
|
77 // CPositionerBase::BaseConstructL |
|
78 // Symbian 2nd phase constructor can leave. |
|
79 // ----------------------------------------------------------------------------- |
|
80 // |
|
81 void CPositionerBase::BaseConstructL(RPositionServer& aServer, |
|
82 TPositionModuleId aModuleId, |
|
83 TPositionModuleInfo::TCapabilities aCapabilities) |
|
84 { |
|
85 JELOG2(EJavaLocation); |
|
86 |
|
87 User::LeaveIfError(iPositioner.Open(aServer, aModuleId)); |
|
88 |
|
89 _LIT(KService, "JavaVM"); |
|
90 iPositioner.SetRequestor(CRequestor::ERequestorService, |
|
91 CRequestor::EFormatApplication, KService); |
|
92 |
|
93 iCapabilities = aCapabilities; |
|
94 |
|
95 // By default, MLFW uses 1K buffer for location information. If the |
|
96 // PSY is capable of providing NMEA statements then the default buffer |
|
97 // runs out very quickly and the buffer size needs to adjusted. This may |
|
98 // cause delays when getting location fixes to Java-side. So if the |
|
99 // module supports NMEA statements then a larger buffer is created |
|
100 // by default. For example, BT GPS PSY receives all NMEA statements |
|
101 // that the module can provide so the default buffer size is not enough |
|
102 // Also the maximum number of fields needs to be changed in that case |
|
103 |
|
104 if (iCapabilities & TPositionModuleInfo::ECapabilityNmea) |
|
105 { |
|
106 iPositionInfo = CreatePositionInfoL( |
|
107 KLocPositionGenericInfoNMEABufferSize, |
|
108 KLocPositionGenericInfoNMEAFieldCount); |
|
109 } |
|
110 else |
|
111 { |
|
112 // Use default values defined in MLFW. Currently 1K for the buffer |
|
113 // size and the maximum number of 32 fields supported. |
|
114 iPositionInfo = CreatePositionInfoL( |
|
115 KPositionGenericInfoDefaultBufferSize, |
|
116 KPositionGenericInfoDefaultMaxFields); |
|
117 } |
|
118 } |
|
119 |
|
120 // ----------------------------------------------------------------------------- |
|
121 // CPositionerBase::~CPositionerBase |
|
122 // ----------------------------------------------------------------------------- |
|
123 // |
|
124 CPositionerBase::~CPositionerBase() |
|
125 { |
|
126 JELOG2(EJavaLocation); |
|
127 delete iPositionInfo; |
|
128 iPositioner.Close(); |
|
129 } |
|
130 |
|
131 // ----------------------------------------------------------------------------- |
|
132 // CPositionerBase::GetQualifiedCoordinates |
|
133 // (other items were commented in a header). |
|
134 // ----------------------------------------------------------------------------- |
|
135 // |
|
136 void CPositionerBase::GetQualifiedCoordinates(CPositionerBase* aSelf, |
|
137 JNIEnv* aJni, jdouble* alatlon, jfloat* aAltHaccVacc, |
|
138 jlong* aTimestamp, jobjectArray aNmeaData) |
|
139 { |
|
140 JELOG2(EJavaLocation); |
|
141 |
|
142 HPositionGenericInfo* posInfo = aSelf->iPositionInfo; |
|
143 |
|
144 const TInt KMaxNmeaSentenceLength = 82; |
|
145 TUint8 numNmeaSentences(0); |
|
146 if (posInfo->GetValue(EPositionFieldNMEASentences, numNmeaSentences) |
|
147 == KErrNone) |
|
148 { |
|
149 HBufC* nmeaData = HBufC::New(KMaxNmeaSentenceLength * numNmeaSentences); |
|
150 if (nmeaData) |
|
151 { |
|
152 TPtr nmeaDataPtr = nmeaData->Des(); |
|
153 TInt lastSentence = EPositionFieldNMEASentencesStart |
|
154 + numNmeaSentences; |
|
155 for (TUint16 i = EPositionFieldNMEASentencesStart; i < lastSentence; ++i) |
|
156 { |
|
157 TBuf8<KMaxNmeaSentenceLength> sentence8; |
|
158 if (posInfo->GetValue(i, sentence8) == KErrNone) |
|
159 { |
|
160 TBuf<KMaxNmeaSentenceLength> sentence; |
|
161 sentence.Copy(sentence8); |
|
162 nmeaDataPtr.Append(sentence); |
|
163 } |
|
164 } |
|
165 |
|
166 jstring jstr = java::util::S60CommonUtils::NativeToJavaString( |
|
167 *aJni, *nmeaData); |
|
168 aJni->SetObjectArrayElement(aNmeaData, 0, jstr); |
|
169 |
|
170 delete nmeaData; |
|
171 } |
|
172 } |
|
173 |
|
174 TPosition pos; |
|
175 posInfo->GetPosition(pos); |
|
176 |
|
177 alatlon[0] = static_cast<jdouble>(pos.Latitude()); |
|
178 alatlon[1] = static_cast<jdouble>(pos.Longitude()); |
|
179 aAltHaccVacc[0] = static_cast<jfloat>(pos.Altitude()); |
|
180 aAltHaccVacc[1] = static_cast<jfloat>(pos.HorizontalAccuracy()); |
|
181 aAltHaccVacc[2] = static_cast<jfloat>(pos.VerticalAccuracy()); |
|
182 |
|
183 *aTimestamp = java::util::S60CommonUtils::TTimeToJavaTime(pos.Time()); |
|
184 } |
|
185 |
|
186 // ----------------------------------------------------------------------------- |
|
187 // CPositionerBase::GetSpeedAndCourse |
|
188 // (other items were commented in a header). |
|
189 // ----------------------------------------------------------------------------- |
|
190 // |
|
191 TInt CPositionerBase::GetSpeedAndCourse(CPositionerBase* aSelf, |
|
192 jfloat* aSpeedCourse) |
|
193 { |
|
194 JELOG2(EJavaLocation); |
|
195 HPositionGenericInfo* posInfo = aSelf->iPositionInfo; |
|
196 |
|
197 if (posInfo->IsFieldAvailable(EPositionFieldHorizontalSpeed) |
|
198 && posInfo->IsFieldAvailable(EPositionFieldHeading)) |
|
199 { |
|
200 TReal32 speed; |
|
201 TReal32 course; |
|
202 posInfo->GetValue(EPositionFieldHorizontalSpeed, speed); |
|
203 posInfo->GetValue(EPositionFieldHeading, course); |
|
204 |
|
205 aSpeedCourse[0] = static_cast<jfloat>(speed); |
|
206 aSpeedCourse[1] = static_cast<jfloat>(course); |
|
207 return KErrNone; |
|
208 } |
|
209 |
|
210 return KErrNotFound; |
|
211 } |
|
212 |
|
213 // ----------------------------------------------------------------------------- |
|
214 // CPositionerBase::GetAddressInfo |
|
215 // (other items were commented in a header). |
|
216 // ----------------------------------------------------------------------------- |
|
217 // |
|
218 TInt CPositionerBase::GetAddressInfo(CPositionerBase* aSelf, JNIEnv* aJni, |
|
219 jobjectArray aAddress) |
|
220 { |
|
221 JELOG2(EJavaLocation); |
|
222 HPositionGenericInfo* posInfo = aSelf->iPositionInfo; |
|
223 TInt availableFields(0); |
|
224 TPtrC ptr; |
|
225 |
|
226 for (TInt i = 0; i < (KNumFields - 2); ++i) |
|
227 { |
|
228 if (posInfo->GetValue(positionField[i], ptr) == KErrNone) |
|
229 { |
|
230 jstring jstr = java::util::S60CommonUtils::NativeToJavaString( |
|
231 *aJni, ptr); |
|
232 aJni->SetObjectArrayElement(aAddress, i, jstr); |
|
233 aJni->DeleteLocalRef(jstr); |
|
234 availableFields |= 1 << i; |
|
235 } |
|
236 } |
|
237 |
|
238 TPtrC8 mediaLinkPtr; |
|
239 if (posInfo->GetValue(EPositionFieldMediaLinksStart, mediaLinkPtr) |
|
240 == KErrNone) |
|
241 { |
|
242 TInt numSlashFound(0); |
|
243 TInt length = mediaLinkPtr.Length(); |
|
244 const TUint8* p = mediaLinkPtr.Ptr(); |
|
245 while (numSlashFound < 2 && length--) // Find second slash |
|
246 { |
|
247 if (*p++ == '/') |
|
248 { |
|
249 ++numSlashFound; |
|
250 } |
|
251 } |
|
252 |
|
253 if (length > 0) |
|
254 { |
|
255 HBufC* mediaLink = HBufC::New(length); |
|
256 if (mediaLink) |
|
257 { |
|
258 mediaLink->Des().Copy(mediaLinkPtr.Right(length)); // Copy URL |
|
259 jstring jstr = java::util::S60CommonUtils::NativeToJavaString( |
|
260 *aJni, *mediaLink); |
|
261 aJni->SetObjectArrayElement(aAddress, KNumFields - 2, jstr); |
|
262 aJni->DeleteLocalRef(jstr); |
|
263 availableFields |= 1 << (KNumFields - 2); |
|
264 delete mediaLink; |
|
265 } |
|
266 } |
|
267 } |
|
268 |
|
269 if (posInfo->GetValue(EPositionFieldBuildingTelephone, ptr) == KErrNone) |
|
270 { |
|
271 jstring jstr = java::util::S60CommonUtils::NativeToJavaString(*aJni, |
|
272 ptr); |
|
273 aJni->SetObjectArrayElement(aAddress, KNumFields - 1, jstr); |
|
274 aJni->DeleteLocalRef(jstr); |
|
275 availableFields |= 1 << (KNumFields - 1); |
|
276 } |
|
277 |
|
278 return availableFields; |
|
279 } |
|
280 |
|
281 // ----------------------------------------------------------------------------- |
|
282 // CPositionerBase::UpdatePosition |
|
283 // (other items were commented in a header). |
|
284 // ----------------------------------------------------------------------------- |
|
285 // |
|
286 void CPositionerBase::UpdatePosition() |
|
287 { |
|
288 JELOG2(EJavaLocation); |
|
289 |
|
290 iPositioner.NotifyPositionUpdate(*iPositionInfo, iStatus); |
|
291 SetActive(); |
|
292 } |
|
293 |
|
294 // ----------------------------------------------------------------------------- |
|
295 // CPositionerBase::IncreaseBufferSizeL |
|
296 // (other items were commented in a header). |
|
297 // ----------------------------------------------------------------------------- |
|
298 // |
|
299 void CPositionerBase::HandleBufferSizeErrorL(const TInt aError) |
|
300 { |
|
301 JELOG2(EJavaLocation); |
|
302 |
|
303 // Increase the size of the buffer by default value. This gets called |
|
304 // repeatedly if the buffer is not big enough for example if the positioning |
|
305 // module is able to handle multiple NMEA sentences as BT GPS PSY does |
|
306 TInt bufferSize = iPositionInfo->BufferSize(); |
|
307 TInt numFields = iPositionInfo->MaxFields(); |
|
308 |
|
309 // Check that what was the overflow situation |
|
310 switch (aError) |
|
311 { |
|
312 case KErrOverflow: |
|
313 { |
|
314 // There are not enough supported fields. |
|
315 numFields += KLocFieldCountIncrease; |
|
316 break; |
|
317 } |
|
318 case KErrPositionBufferOverflow: |
|
319 { |
|
320 // The buffer size was not enough as the positioner provided |
|
321 // more information than expected. Try to increase buffer size |
|
322 bufferSize += KLocBufferSizeIncrease; |
|
323 break; |
|
324 } |
|
325 default: |
|
326 { |
|
327 // Unkown buffer size error. Should newer get here because MLFW |
|
328 // does not return any other buffer overflow situations and |
|
329 // base classes should take care about other situations |
|
330 __ASSERT_DEBUG(EFalse, User::Invariant()); |
|
331 break; |
|
332 } |
|
333 } |
|
334 |
|
335 // Create new buffer. Capabilities needs to be the same as in the original |
|
336 HPositionGenericInfo* newInfo = CreatePositionInfoL(bufferSize, numFields); |
|
337 delete iPositionInfo; |
|
338 iPositionInfo = newInfo; |
|
339 } |
|
340 |
|
341 // ----------------------------------------------------------------------------- |
|
342 // CPositionerBase::CreatePositionInfoL |
|
343 // (other items were commented in a header). |
|
344 // ----------------------------------------------------------------------------- |
|
345 // |
|
346 HPositionGenericInfo* CPositionerBase::CreatePositionInfoL( |
|
347 const TInt aBufferSize, const TInt aNumFields) const |
|
348 { |
|
349 JELOG2(EJavaLocation); |
|
350 HPositionGenericInfo* posInfo = HPositionGenericInfo::NewL(aBufferSize, |
|
351 aNumFields); |
|
352 |
|
353 // Request speed and direction if supported by the module |
|
354 if ((iCapabilities & TPositionModuleInfo::ECapabilitySpeed) |
|
355 && (iCapabilities & TPositionModuleInfo::ECapabilityDirection)) |
|
356 { |
|
357 User::LeaveIfError(posInfo->SetRequestedField( |
|
358 EPositionFieldHorizontalSpeed)); |
|
359 User::LeaveIfError(posInfo->SetRequestedField(EPositionFieldHeading)); |
|
360 } |
|
361 // Request NMEA statements if supported by the module |
|
362 if (iCapabilities & TPositionModuleInfo::ECapabilityNmea) |
|
363 { |
|
364 User::LeaveIfError(posInfo->SetRequestedField( |
|
365 EPositionFieldNMEASentences)); |
|
366 } |
|
367 if (iCapabilities & (TPositionModuleInfo::ECapabilityAddress |
|
368 | TPositionModuleInfo::ECapabilityBuilding |
|
369 | TPositionModuleInfo::ECapabilityMedia)) |
|
370 { |
|
371 for (TInt i(0); i < KNumFields; i++) |
|
372 { |
|
373 User::LeaveIfError(posInfo->SetRequestedField(positionField[i])); |
|
374 } |
|
375 } |
|
376 return posInfo; |
|
377 } |
|
378 |
|
379 // End of File |